LUCA DAN ŞERBĂNAŢI

CRENGUŢA BOGDAN

PROGRAMAREA ORIENTATĂ SPRE OBIECTE

NOTE DE CURS

2006

CONŢINUT 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. RELAŢIA DE GENERALIZARE/SPECIALIZARE ÎNTRE CLASE .........15
MOŞTENIREA ÎN JAVA ................................................................................................................16

4. ARRAY-URI ..........................................................................................22
INIŢIALIZAREA 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 MOŞTENIREA .................................................................................................37 UTILIZAREA CLASELOR INTERNEÎN APLICAŢII OO.........................................................................38

8. INPUT/OUTPUT ÎN JAVA.....................................................................41 9. GESTIUNEA EXCEPŢIILOR ................................................................53 10. COLECTII .............................................................................................60
STRUCTURI DE DATE DINAMICE ..................................................................................................60 TIPOLOGII DE COLECŢII ..............................................................................................................60 COLECŢII Î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

2

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 său 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; }

3

int oraCurenta=c. sau 4 . Principiul OO care sta la baza definirii interfetei unui obiect este cel al incapsularii informatiilor (“information hiding”). Desi obiectele se diferentiaza prin stare. identitatea acestuia este data de valoarea atributului numar de identificare. return false. Totalitatea elementelor ce pot fi accesate din exteriorul obiectului formeaza interfata acestuia. Implementarea unei operatii in limbajul Java se numeste metoda. vrea sa stie daca magazinul cu numarul de identificare 10 este deschis sau nu.prototipul metodei = contine elementele de declarare a metodei . Pana acum.} D. Conform acestui principiu. interfata obiectului 10 este formata din metodele publice fara sa dam acces direct la variabilele instanta.HOUR_OF_DAY). CONCEPTE Un obiect este o instanta (sau exemplificare) a unui concept. Un alt exemplu il constituie cazul in care proprietarul. In cazul obiectului 10. O metoda se caracterizeaza prin urmatoarele elemente: . In acest caz. 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. 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. Rezulta ca starea unui obiect poate fi modificata numai prin intermediul interfetei lui. ca orice client al obiectului 10. D. dar care sa fie diferite. D.Nivelul specificarii (limbajul UML) + obtineOrar(): String Nivelul implementarii (limbajul Java) public String getOrar(){ return oraDeschidere+”:00-” +oraInchidere+”:00”. Adica. Elementele de structura si functionalitate ale unui obiect pot fi proiectate pentru a fi accesibile din afara obiectului. De exemplu. if (oraCurenta>=oraDeschidere && oraCurenta<=oraInchidere) return true. In acest caz ele sunt variable private.getInstance(). } if (esteDeschis()) return “Este deschis!”. Observatie.definitia metodei = corpul metodei ce contine instructiuni ce implementeaza algoritmul operatiei.get(Calendar. spunem ca atributul (proprietatea) numar de identificare furnizeaza un criteriu de identitate pentru obiectele de acelasi tip. orice client (inclusiv proprietarul) are acces la operatiile obiectului 10 deoarece operatiile respective sunt publice.unor entitati concrete: lucruri care ne inconjoara sau fapte care se petrec de-a lungul timpului. puteam avea doua obiecte cu aceeasi stare. Un concept este o idee sau o notiune care se aplica: .semnatura metodei = combinatie intre numele metodei si tipul parametrilor in ordinea declararii lor . else return “Este inchis!”. aceasta din urma nu asigura identitatea obiectelelor.

copac marca de masina. inregistrare automobil achizitie on-line a unor produse. Azor Mercedes Fundatia Oamenilor de afaceri Magazinul Tomis. picior de masa. roi de albine elev intr-o clasa. buton intr-o fereastra. profesor. Conceptele pot fi clasificate in mai multe categorii: Categorie Exemple de concepte tangibil persoana. inregistrator de casa sistemul informatic al serviciului personal. 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. vizita medicala. sistemul de contabilitate. rezervarea pentru o persoana in rezervarea unei excursii in grup trimitere mesaj. sistemul de autorizare a utilizarii unui card bancar factura. înscriere la universitate. proprietar. memorarea sosirii unui mesaj in sistem. documentatie de proiect firma. comanda de 5 Instante de concepte colegul Ionescu. Torent Computers colegul Ionescu. admitere clasa de elevi. rezervare. motor. profesor.semantica: ideea sau notiunea la care se refera numele. pisica. caine artefact.o extensie data de multimea instantelor conceptului. masina. Un concept se caracterizeaza prin trei elemente: . asociatie familiala vanzare. medic. log-are. casa. modem. angajat casatorie. masina. administrator. revizie. oras pilot.unor entitati abstracte cum ar fi constructiile noastre mentale. masa. autor. contractare. inchiriere articol dintr-o vanzare de mai multe produse. banca. firma persoana. fundatie magazin. . fereastra de componente grafice. masina. cumparare. .nume: cuvantul pe care-l folosim cand ne referin la acel concept.. specificatia unei aplicatii OO. port. albina vitezometru. student. masina mea 17:23. portul Constanta inregistrari de contracte sau evenimente . agentie de voiaj.

O clasă descrie instantele unui concept. } public String getMesaj(){ if (esteDeschis()) return “Este deschis!”. CLASE DE OBIECTE D. Din acest motiv. ecuatie Observatie. else return “Este inchis!”. 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. private String denumire. integrala. Categoriile de concepte nu sunt ortogonale (adica. O clasa poate defini variabile si metode de clasa. De exemplu. public int getOraInchidere(){ return oraInchidere. Asadar. O clasă este o descriere a unei mulţimi de obiecte care au aceleaşi atribute. numeProprietar. 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. } public int getOraDeschidere(){ return oraDeschidere. multime. valoarea unei variabile de clasa este partajata de toate obiectele clasei respective. int oraCurenta=c. Atributele si operatiile obiectelor sunt implementate in Java ca variabile instanta. 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.HOUR_OF_DAY).get(Calendar. aceleaşi relaţii cu alte clase şi aceeaşi semantică.getInstance(). O variabila de clasa implementeaza un atribut al clasei si nu al obiectelor sale. if (oraCurenta>=oraDeschidere && oraCurenta<=oraInchidere) return true. respectiv metode instanta. Unitatea de baza a limbajului Java (ca orice limbaj orientat spre obiecte) este clasa. independente intre ele). private int oraDeschidere. } } Observatie. } private boolean esteDeschis(){ Calendar c=Calendar. oraInchidere. aceleaşi operaţii. 6 .Exemple de concepte Instante de concepte achizitie concepte abstracte calendar gregorian. un concept putand sa apartina mai multor categorii. un program Java contine cel putin o clasa. return false. Valoarea reprezinta numarul de identificare al noului obiect.

String numeP) { this(numeM. numere reale. vor avea aceeasi structura: atribute si operatii. oraDeschidere=oraD. 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. O clasa este un model pentru obiectele sale. Acesta nu are parametri si initializeaza cu valori implicite sau cu valorile definite in sectiunea de declarare a variabilelor instanta. De exemplu. inclusiv obiecte dupa diferite criterii. Se numesc clase utilitare si furnizeaza servicii globale. } this = Cuvânt cheie care se utilizează în interiorul corpului unei metode instanţă şi care furnizează referinţa la obiectul pentru care a fost apelată metoda. clasa Arrays contine metode de sortare a elementelor unui array de numere intregi. String numeP) { //Constructor nrIdentificare=idCurent++ . acestia vor fi spuraincarcati.este apelat prefixandu-l cu operatorul new. oraInchidere=18. numeP. O clasa este o fabrica pentru obiectele sale. Se numeste constructor implicit deoarece este furnizat de Java.nu are tip al rezultatului . clasa Magazin are un constructor. daca este necesar.Se pot proiecta si implementa clase care au numai metode statice. 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. denumire=numeM. De exemplu. adica au acelasi nume si difera prin numarul si/sau tipul parametrilor.are acelasi nume ca numele clasei . 18). } În UML reprezentăm relaţia de instanţiere dintre o clasă şi un obiect al său ca o dependenţă clasă instanţă a Magazin Tomis: Magazin obiect 7 . Sau altfel supus. 10. In cazul in care o clasa are mai multi constructori. clasa Magazin ar putea avea doi constructori: public Magazin(String numeM. O clasa poate defini explicit unul sau mai multi constructori care sa realizeze initializarea variabilelor instanta si eventual modificarea variabilelor de clasa. Alte caracteristici ale unui constructor: . caractere. D. numeProprietar=numeP. oraInchidere=oraI. Asadar. Intr-un constructor se poate apela un alt constructor al aceleaşi clase. semnatura lor difera numai prin numarul si/sau tipul parametrilor. String numeP. } public Magazin(String numeM. De exemplu. al doilea constructor ar putea fi definit astfel: public Magazin(String numeM. int oraI) { //Constructor nrIdentificare=idCurent++ . deoarece orice clasa are cel putin un constructor. toate obiectele clasei Magazin. int oraD. oraDeschidere=10. denumire=numeM. numeProprietar=numeP. De exemplu.

In acest sens putem spune ca obiectele comunică între ele prin intermediul metodelor. “Popescu”. atunci puteam folosi operatorul punct pentru a accesa valorile acestora. Al doilea operand este chiar numele metodei urmat de lista parametrilor efectivi. De exemplu. Apelul metodei intrerupe executia metodei curente si trece controlul metodei apelate. De obicei un apel de metoda are loc in momentul in care obiectul apelant executa o metoda a sa. exact in punctul de intrerupere. Accesul la o metoda este stabilit de regulile de vizibilitate din Java. controlul revine la metoda intrerupta. 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. apelul unei metode apartinand unui obiect din interiorul unei metode che apartine aceluiasi obiect se face fara a utiliza operatorul “. Nota. Daca metoda apelata restituie (intoarce) o valoare metodei apelante.“Ion”). “Ionescu Pop”). ele sunt modificate sau folosite cu NumeClasa. in cazul general.numeVariabilaClasa.” si fara a utiliza referinta la obiectul destinatie. 8 . aceasta valoare poate participa la calculul unei expresii devenind un operand in acea expresie. De exemplu. La sfarsitul executiei metodei apelate.”. daca aceastea furnizeaza acces. Pentru a putea apela o metoda M a unui obiect B. 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(). In cazul in care o variabila instanta furnizeaza acces. un obiect A trebuie sa aiba acces la metoda M. Accesarea variabilelor Variabilele m1 si m2 ar putea fi folosite pentru a accesa valorile variabilelor instanţă. vom scrie o alta clasa TestMagazin care. Apelarea unei metode se face cu ajutorul operatorului binar “. Magazin m2 = new Magazin(“Constanta”. Acest obiect este subinteles a fi obiectul curent in care ne aflam cu executia. sunt create două obiecte din clasa Magazin şi se memoreaza referinţele la ele în variabile de acelaşi tip: Magazin m1 = new Magazin(“Tomis Mall”. Este cazul in care apelul de metoda apare in interiorul unei expresii sau in locul unei expresii. De exemplu. Aceasta metoda poate sa apartina obiectului apelant (apel intern) sau.getMesaj(). in metoda main(). Apelul de metodă D. Relaţia de instanţiere O clasa furnizeaza un tip de date cu care putem declara variabile referinta de acest tip. 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. In cazul apelurilor de metode ale clasei (este cazul metodelor declarate static). In cazul variabilelor de clasa. poate sa apartina unui alt obiect. Ca si in cazul variabilelor-membru. m1. regula de construire a apelului este aceeasi doar ca primul operand trebuie sa fie chiar numele clasei. daca ne dau voie.Diagrama 1. Apelul unei metode poate fi vazut si ca un mesaj pe care obiectul apelant il trimite obiectului apelat.

aplicatia va afisa urmatoarea interfata grafica: Datele clientilor sunt memorate intr-un fisier numit “clienti. si actionarea tastei Enter. 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. clientul (sau oricine este interesat) actioneaza butonul “Date despre magazin”. la urmatoarele operatii. a. 9 . aplicatia atentioneaza clientul ca este nou si trebuie sa introduca adresa. adresa acestuia este citita din fisier si afisata in campul de text: Adresa. dupa introducerea numelui si prenumelui său. Specificatia proiectului Magazinul Tomis emite facturi pe baza produselor vandute clientilor. Cand este executata.i. proprietarul magazinului a decis sa cumpere de la o firma de software o aplicatie care se realizeze acest lucru. Pentru a gestiona automat facturile emise de magazin.txt”. Daca este vorba de un client “vechi”.2. aplicatia afiseaza fereastra principala: Pentru a vizualiza date despre magazin. Daca este vorba de un client nou. In acest moment. iar aplicatia va afisa urmatoarea interfata grafica: Pentru a realiza o vanzare. clientul sau casiera trebuie sa actioneze butonul “Comandati produse” din ferestra principală. acestia vor fi recunoscuti.

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

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

o cunoastere unilaterala sau bilaterala. latime : Integer) : String 12 .Un obiect foloseste un alt obiect.bilateral (cele doua obiecte se cunoasc intre ele) D. . ElementVanzare cantitate : Integer ElementVanzare(p : SpecificatieProdus. O legatura (link) in abordarea orientata spre obiecte este o conectare fizica.* 1 getAdresa() estePentru Factura nrFactura : Integer data : Calendar formatare(sir : String.. numarul de obiecte care participa in relatia de asociere si roluri. 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.obiectele unei clase partajeaza cu alte obiecte obiectele celei de-a doua clase.Un obiect trimite mesaje unui alt obiect. conceptuala. 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: . de aceea exista intotdeauna posibilitatea ca un obiect sa-si trimita sieşi un mesaj. 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. O asociere intre doua clase poate indica: . 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.un raport de tip client-furnizor intre obiectele celor doua clase. .Un obiect anunta un alt obiect? O asociere se caracterizeaza prin urmatoarele elemente: nume. . dar al doilea nu) . cerandu-i acestuia din urma sa-si modifice starea? . Link-ul poate fi: . sintactica (semantica sau sintactica) sau logica intre doua obiecte.D. fiindca are nevoie de informatii de la acesta din urma? . directia de folosire.unilateral (primul obiect il cunoaste pe al doilea.o cale de comunicare intre obiectele celor doua clase. Orice clasa are implicit o relatie de asociere cu ea insasi. multiplicitate.

in clasa A. this. } } public ElementVanzare(SpecificatieProdus p. } public SpecificatieProdus getProdus(){ return produs. int pret){ this. 13 . 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.Abstractizare. } public long calculeazaCost(){ return produs. private int cantitate.pretUnitar=pret. public class SpecificatieProdus{ private String denumire. cantitate=c. private int pretUnitar. } } public class TestArticol{ public static void main(String[] args){ ElementVanzare a1=new ElementVanzare(new SpecificatieProdus("tastatura".calculeazaCost()).Nivelul de implementare Orice asociere va fi implementata cu ajutorul unui atribut de tip clasa B. Proces care capteaza caracteristicile esentiale ale unui obiect. int c){ produs=p. } public int getPret(){ return pretUnitar. 1000). daca acesta a fost specificat. 3).getPret()*cantitate. Numele atributului este dat de rolul asocierii. System. public SpecificatieProdus(String denumire. } public int getCantitate(){ return cantitate.println(a1.out. } Principiile paradigmei orientarii spre obiecte Orice aplicaţie orientată pe obiecte trebuie să fie construită folosind patru mecanisme conceptuale: 1.denumire=denumire. } public String getDenumire(){ return denumire. caracteristici ce diferentiaza acest obiect de toate celelalte tipuri de obiecte.

Reprezinta proprietatea unui obiect de a continua sa existe dupa ce creatorul său a incetat sa mai existe sau de a fi mutat din locul în care a fost creat în altul. Toate obiectele au o identitate proprie: obiectele sunt distincte intre ele. Generalizarea/specializarea reprezinta un al doilea mecanism de clasificare: obiectele se clasifica în clase. instante. 14 . Generalizarea este o relatie intre clase in care structura si comportamentul comun a doua sau mai multor clase este incapsulat intr-o singura clasa. Proces mental executat pe o abstractizare în care elementele structurale ale abstractizarii sunt izolate de cele ce constituie comportamentul sau. Din faptul ca clasele si obiectele derivate din clase incapsuleaza într-un singur “pachet” datele si operatiile. Este o constrângere 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). 2. atribute. Cunostintele sunt descrise în termeni de clase. iar clasele se clasifica prin intermediul superclaselor.Ierarhie.Incapsulare. Polimorfism. Proprietatea unei aplicaţii care a fost descompusă într-un ansamblu de module (pachete) cu o mare coeziune interna si cu legaturi slabe intre ele. operatii. 4. Alte două concepte de importanta mai mica caracterizeaza obiectele intr-o modelare pe obiecte: 1. Un obiect care trimite un mesaj nu trebuie sa se preocupe de structurile interne de date ale obiectului destinatar.Typing. Metoda utilizata pentru ordonarea cunostintelor despre obiecte. Specializarea este o relatie între clase în care o clasa (superclasa) îsi transmite structura si functionalitatea uneia sau mai multor clase (subclase). 4.2. deriva avantaje importante: • Detaliile interne de implementare si ale procedurilor sunt invizibile in exterior (information hiding). Este o relaţie de ordine între abstractizari care sunt tipuri abstracte de date. Aceasta faciliteaza reutilizarea componentelor. Serveste la separarea interfetei vizibile a unei abstractizari de implementarea sa. 3. Clasificare. Aceasta reduce propagarea efectelor in cazul modificarilor. Aceasta din urma va fi supraclasa pentru primele clase. Persistenta (persistence). În general. 1. Caracteristicile abordarii orientate pe obiecte Proprietatilor obiectelor si a mecanismelor de structurare a universului OO au drept consecinte urmatoarele caracteristici ale abordarii OO: 1. Polimorfismul este două tipuri: static (prin supraincarcarea metodelor) şi dinamic (prin redefinirea metodelor). • Structurile de date si operatiile sunt definite intr-o entitate cu nume: clasa. 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. 3. Proprietate a unui obiect care il diferentiaza de alte obiecte. Identitate. Există două tipuri de ierarhii: bazate pe relaţia de generalizare/specializare şi cele bazate pe relaţia de agregare. Se reduce astfel incarcarea sistemului.Modularitate. • Interfetele intre obiecte sunt simplificate. Proprietatea unei operatii de a putea fi aplicata în moduri diferite mai multor clase. Generalizare/Specializare.

având aceeaşi structură şi aceleaşi operaţii cu cele ale obiectelor din supraclasă. iar Y este specializarea lui X. Y Într-o relaţie de generalizare/specializare un obiect al unei subclase este şi obiect al supraclasei clasei respective. Sef. Dar. În această relaţie. in aplicatia Magazin clientul este o persoana care are o adresa. iar Y subclasă. De exemplu. clasa Angajat. vom spune că Y este un tip de X care …. RELAŢIA DE GENERALIZARE/SPECIALIZARE ÎNTRE CLASE Am văzut că a program spre obiecte înseamnă a raţiona în termeni de concepte. iar Y este conceptul derivat. Relaţia de generalizare/specializare se păstrează şi între clasele care reprezintă cele două concepte. În UML. dar au ceva în plus (sau ceva specific) faţă de X. Somer. ce poate fi diferit în subclasă faţă de supraclasă? Una sau mai multe proprietăţi (variabile) specifice subclasei respective. dar au ceva diferit sau în plus. 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 . unde X şi Y sunt concepte. De exp. X este conceptul de bază. Specializarea tipului client determina aparitia a inca 3 concepte: Angajat. această relaţie între clase este arătată astfel: X X se mai numeşte superclasă (sau supraclasă).3. Această relaţie particulară dintre concepte se numeşte relaţia de generalizare/specializare şi indică faptul că toate instanţele lui Y sunt şi instanţe ale lui X. Mai general. Se mai spune că X este generalizarea lui Y.

else if(3<=catVechime && catVechime<7) salariu+=7*salariu/100. public void setCostOra(double c){ costOra=c. salariu. precum Java. Această moştenire are două aspecte: structura obiectelor şi modul lor de comportament. De exp. subclasa poate adăuga unul sau mai multe comportamente specifice sau să le modifice pe cele moştenite din supraclasă. else salariu+=15*salariu/100. public String getNume(){return nume. În aplicaţia noastră.} public void setCatVechime(int c){ catVechime=c. 16 . MOŞTENIREA ÎN JAVA Relaţia de generalizare/specializare dintre concepte sau clase induce ideea unei moşteniri pe care o subclasă o primeşte de la supraclasa sa. else if (7<=catVechime && catVechime<10) salariu+=10*salariu/100. public void setAdresa(String n){adresa=n. subclasa respectivă trebuie să definească propriile variabile şi metode. } public double getSalariu(){return salariu.} public void calculeazaSalariu(int nr){ salariu=nr*costOra. iar NumeSuperClasa este superclasa sa. se propune un mecanism numit moştenire. şi aproape întotdeauna în aceste situaţii. Aşadar.} } public class Client extends Persoana{ private String adresa. Iată structura celor două clase: public class Persoana{ private String nume. } public String getAdresa(){return adresa. private int catVechime. Acest mecanism permite unei noi clase să beneficieze de structura şi comportamentul definite într-o clasă deja existentă prin declararea că moştenim acea clasă. } } public class Angajat extends Client{ private double costOra..} public String getPrenume(){return prenume. Apoi. prenume. Declararea că o clasă extinde o altă clasă este indicată în Java prin cuvântul cheie extends în declaraţia clasei respective: class Identificator extends NumeSuperClasa { //definim variabile şi metode specifice subclasei } unde Identificator este numele subclasei. o clasă poate extinde o singură clasă. if(catVechime<3) salariu+=5*salariu/100. mecanismul de moştenire se numeşte extensia clasei existente şi cere subclasei să declare ce clasă extinde. Pentru a reprezenta relaţia de generalizare/specializare în limbajele de programare spre obiecte.Apoi.} } public class Somer extends Client{ private int procentDeCalcul. subclasele pot adăuga ceva specific. moştenirea este simplă. clasa Manager este o subclasă a clasei Angajat. In Java. În Java. Regulă.

o clasă poate redefini una sau mai multe metode moştenite din clasa Object.Object().lang.0. Orice clasă extinde direct (implicit sau explicit) sau indirect clasa Object. redefinirea este folosită mai puţin şi este vorba de fapt de ascunderea variabilelor din supraclase. De aici putem concluziona că: O subclasă moşteneste toate variabilele şi metodele neprivate ale supraclasei pe care o extinde. clasele formează o structură de arbore în care rădăcina este clasa Object. a cărei definiţie apare în pachetul java. Un obiect al unei subclase este alocat in memorie intr-o zona care include atat spatiul alocat obiectului superclasei. trebuie să îndeplinească următoarele condiţii: . Dacă doreşte. acesta trebuie să dea cel puţin la fel de mult acces ca metoda moştenită din supraclasă. public class Sef extends Angajat{ private double sporConducere. cat si spatiul necesar variabilelor declarate in subclasa. 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ă posibilităţi: . Structura clasei Object este următoarea: public class Object { public java. } } În cazul variabilelor instanţă. toate clasele definite de programator care nu extind o altă clasă sunt automat subclase ale clasei Object. Rămâne posibilitatea accesării variabile private prin intermediul metodelor set şi get.să redefinească membrii superclasei. super = Cuvânt cheie care se utilizează în interiorul corpului unei metode a unei instanţe a unei clase pentru a indica obiectul superclasei ce intra in structura instantei curente. salariu+=sporConducere.să adauge membri noi si/sau .lang.} public double calculeazaAjutor(double salariuMediu){ return salariuMediu*procentDeCalcul/100. Variabila salariu este protected in Angajat. public void setSporConducere(double s){ sporConducere=s.metoda redefinită trebuie sa aibă exact aceeaşi semnătură.dacă metoda redefinită îşi schimbă modificatorul de acces. Dacă o metodă este redefinită în subclasă. . Nota. . } } Vizibilitatea membrilor în subclase Variabilele instanţă private ale unei supraclase nu sunt moştenite în subclasele ei. Aşadar.metoda redefinită trebuie să aibă acelaşi tip al rezultatului întors.calculeazaSalariu(nr). Ierarhia claselor Java În Java.public void setProcent(int p){procentDeCalcul=p. Exemplu.} public void calculeazaSalariu(int nr){ salariu=super. 17 .

this. prenume). clasa String redefineşte această metodă pentru a compara lexicografic şirurile conţinute în cele două obiecte care se “compară”. oricare din aceste metode poate fi apelată asupra oricărui obiect.adresa=adresa. public final native void notifyAll(). public final native java. public final native void wait(long) throws InterruptedException.String toString(). Metoda equals() permite compararea oricăror două obiecte. deoarece sunt private.adresa=adresa. this. Constructori şi moştenirea După cum ştim.lang. protected native java. cum ar fi de exemplu toString() sau equals().Class getClass(). this. int) throws InterruptedException. String adresa){ setNume(nume).Object).lang. Dacă această metodă nu este redefinită. public boolean equals(java. Rezultatul este true numai dacă cele două obiecte sunt de fapt acelaşi obiect. Presupunem că clasa Persoana contine următorul constructor: public Persoana(String n. Chiar dacă schimbăm modificatorul de vizibilitate al variabilelor nume şi prenume. metodele clasei Object sunt moştenite de toate clasele Java. protected void finalize() throws Throwable. nu putem scrie un constructor în clasa Client care să iniţializeze direct variabilele nume şi prenume.lang. De aceea. mai ales când variabilele instanţă ale supraclasei nu sunt moştenite. De exemplu.lang. dar la compilare vom avea eroare: nu cunoaşte constructorul fără parametri al supraclasei Persoana. String adresa){ super(nume. oridecâte ori se doreşte afişarea unor informaţii despre un obiect (cum ar fi starea obiectului) se va rescrie metoda toString().prenume=prenume. 18 . se poate redefi această metodă dacă dorim ca metoda să realizeze un alt tip de comparare. String prenume){ nume=n. String prenume. public native int hashCode(). O soluţie ar fi să apelăm metode setNume() şi setPrenume() care sunt moştenite de clasa Client şi am avea următorul constructor: public Client (String nume. setPrenume(prenume). constructorii încapsulează algoritmi de iniţializare a obiectelor ce vor fi create.Object clone() throws CloneNotSupportedException. public final native void wait(long. } Datorită observaţiei anterioare. vom avea aceeaşi eroare de compilare. Datorită ierarhiei claselor Java. Dar. } Codul este corect. În consecinţă. String prenume. Cunoaştem deja unele metode din clasa Object.} public java. atunci va fi afişată numele clasei din care face parte obiectul respectiv împreună cu un şir ce reprezinta codul hash al obiectului în memoria heap. Când este vorba de un obiect al unei subclase este important să ştim cum va fi iniţializată partea obiectului ce aparţine structurii supraclasei. public final void wait() throws InterruptedException. public final native void notify(). Metoda toString() furnizează o “reprezentare” sub formă de şir a unui obiect. O soluţie bună ar fi să folosim cuvântul cheie super şi apelăm constructorul cu doi parametri din clasa Persoana: public Client (String nume.

Din acelaşi motiv. Constructor predefinit A() Clasa A 2: A() 6: algoritmul lui A() …. Şi tot aşa. atunci acest apel (folosindu-se super) se face pe prima linie a corpului constrcutorului respectiv. fără parametri. Aşadar avem două soluţii: .setSporConducere(100). Dacă intr-un constructor al unei subclase se apelează un constructor al supraclasei sale. Aceasta are un singur constructor.//metoda instanta definita in clasa Sef s1. care nu are parametri. Cu această clasă este creat obiectul şi apoi este iniţializat pe drumul invers al apelului cu executarea Constructor Object() Clasa Object 4: Object() 5: initializeaza obiect …. atunci caută constructorul fără parametri al supraclasei clasei respectiv. Constructor X(…) Clasa X 7: algoritmul lui X(…) 1: X(…) new X(…) Crearea unui obiect în Java algoritmilor din constructorii supraclaselor până la clasa respectivă (Figura 6-2). putem crea obiecte ale clasei Sef şi apela metodele lor astfel: Sef s1=new Sef("Ionescu". „Aleea rozelor”. Dacă supraclasa nu are un constructor fără parametri. „Pop”. deoarece înainte de a executa algoritmul respectiv. mediul Java apelează automat constructorul fără parametri al supraclasei dacă acesta poate fi apelat. putem memora într-o variabilă de tip Angajat o referinţă la un obiect al clasei Sef: 19 . Mecanismul de iniţializare a obiectelor Apelul unui constructor nu este un apel al unei metode oarecare. până când clasa Object este supraclasa clasei respective.//metoda mostenita din Angajat s1.setCatVechime(25).în supraclasa Angajat introducem încă un constructor.} Regulă.//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 moştenite din supraclasa Angajat. 7). Utilizarea obiectelor ale subclaselor Având clasa Sef definită ca subclasă a clasei Angajat.folosim super şi apelăm un anumit constructor din supraclasă .//constructorul s1.calculeazaSalariu(200).

„Aleea stejarilor”.calculeazaSalariu(160). subclasele pot redefini aceeaşi metodă de mai multe ori. Dacă într-o variabilă de tip supraclasa unei clase va fi memorată o referinţă la un obiect al subclasei respective. în funcţie de propriile necesităţi. dacă apelăm o metodă ce aparţine numai clasei Sef şi nu clasei Angajat. putem folosi operatorul instanceof pentru a accesa variabilele şi metodele obiectului referit de variabilă.//eroare la compilare! După cum se observă. După cum se observă avem două cazuri: . atunci obiectul accesat prin intermediul varibilei referinţă. „Marin”.//se apeleaza metoda definita in clasa Sef s2. comportându-se ca un obiect al supraclasei. s2.metoda respectivă este moştenită din clasa Clasa1 şi nu a fost redefinită în ierarhia sa directă: Clasa5 şi Clasa3. În plus. Atunci. va fi metoda din Clasa3. valoarea expresiei ar fi fost false. Atunci ar trebui să vedem cum va fi rezolvat un apel de metodă aplicat unui obiect dintr-o subclasă. metoda este definită iniţial în clasa Clasa1 şi redefinită în Clasa3. … } Mecanismul apelarii metodelor într-o ierarhie de clase Am văzut că în cazul moştenirii.setSporConducere(150).setNume("Georgescu"). Aşadar. dacă vrem să folosim pe deplin obiectul respectiv (adică. Regulă. Atunci metoda care va fi executată va fi metoda din Clasa1 (Figura 6-3 a). expresia s2 instanceof Sef are valoarea true deoarece referinţa memorată în variabila s2 indică un obiect al clasei Sef. un obiect al unei subclase poate fi folosit pentru a apela metode definite în clasa respectivă. adică de tip supraclasă. compilatorul va genera o eroare pentru că variabila s2 a fost declarată de tip Angajat. conform clasei din care face parte) folosim operatorul instanceof împreună cu operatorul cast la clasa originală: if (s2 instanceof Sef){ Sef s3=(Sef) s2. pierde temporar specificul subclasei. Atunci metoda care va fi executată. În acest caz. dar şi metode definite în supraclasa sa directă sau în supraclasele sale îndirecte şi moştenite de clasa sa. De exemplu. Altfel. 10).//metoda mostenita din Persoana s2. dacă avem o variabilă de tip supraclasă nu suntem siguri că obiectul referit de variabilă este de tip supraclasă. 20 . Astfel presupunem că un obiect a apelează o metodă a obiectului b din Clasa5 din figura următoare.Angajat s2=new Sef("Marinescu".

Definiţia metodei Definiţia iniţială a metodei Clasa1 4 Clasa2 3 Clasa3 3 Clasa1 Metoda redefinită Clasa2 Clasa3 Clasa4 Clasa5 2 Clasa4 Clasa5 2 Obiect a 1 Obiect b Obiect a 1 Obiect b Obiect Observăm că. 21 . este transmis în sus în ierarhia de clase până când este găsită o primă definiţie a metodei apelate. apelul unei metode a unui obiect aparţinând unei subclase. dacă metoda apelată nu este definită in subclasă.

fie o expresie cu valoare dreapta un numar intreg. umplerea array-ul cu aceste valori se face astfel: for (int i=0. un array trebuie să fie creat (alocat) cu new. array-urile propriu-zise nu exista in memorie.i++) personal[i]=new Persoana(). \u0000 (tipul char). elementele array-ului se pot umple cu valori. Elementele unui array sunt ordonate dupa unul sau mai multe criterii numite dimensiuni. false (tipul boolean) sau null (tipuri referinţă). personal = new Persoana[1000]. De exemplu. După creare. sau TipDeDate id[]. Referinţa la un array va fi memorată într-o variabilă array. valoarea expresiei personal. Aceste valori se numesc elementele array-ului. care trebuia sa fie create. In acest moment. 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. Un array furnizează spaţiu pentru valorile de tip primitiv sau referinţă la obiectele de un acelaşi tip. Pentru a exista într-un program. In cazul array-ului de tip referinta personal. Dupa numarul de dimensiuni. Dupa executarea acestor declaratii. numere = new int[5]. Astfel. De exemplu. De exemplu. daca arrayul numere contine primele 5 numere pare naturale. O dimensiune a unui array este indicata printr-o pereche de []. putem declara două variabile array numere şi personal astfel: int[] numere. iar cele ale array-ului personal cu valoarea null. ARRAY-URI Array = O colecţie liniară de elemente în care fiecare element este accesibil prin intermediul unui indice. INIŢIALIZAREA UNUI ARRAY Am vazut ca la momentul creării unui array. ci numai variabilele array asociate. Nota.i++) numere[i]=2*i. De exemplu. for (int i=0. valorile lui sunt referinte catre obiecte de tip Persoana. 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.4. lungimea unui array este egala cu numărul de elemente ale array-ului. Sintaxa alocarii memoriei unui array este: id = new tip[expresie] unde tip este tipul de date al variabilei array cu identificatorul id. Sintaxa este urmatoarea: TipDeDate[] id={listaDeInitializatori} 22 . cu observatia ca indicele unui array începe de la 0. i<1000. i<5. Sintaxa declararii unei variabile array unidimensional este urmatoarea: TipDeDate[] id.sau multidimensional. un array este uni. elementelor sale le sunt atribuite valoarea zero (tipuri primitive numerice). iar expresie este fie un literal intreg. Persoana personal[]. toate elementele array-ului numere sunt initializate cu 0.length este 1000. Grafic. Astfel un array cu 10 elemente va avea indicele de la 0 la 9. Pentru a determina lungimea unui array se foloseste variabila length.

i<a3. j++) for(int k=0. Similar.// a doua linie are 4 elemente Nota: Daca numarul coloanelor poate sa difere. declararea unei matrici m cu elemente de tip intreg se realizeaza astfel: int[][] m. k<a2[i][j]. j++) for(int k=0. //b are 2 linii b[0]=new int[3]. static int pRand(int mod) { return Math. un array multidimensional este memorat ca un array de array-uri (si la randul lor pot fi de array-uri). i++) for(int j = 0. In cazul array-urilor multidimensionale variabila length are valori diferite. In memorie. De exemplu. pe cand b[1]. k<a3[i][j].length. } public static void main(String[] args){ //array 3-D cu dimensiuni fixe: int[][][] a2 = new int[2][2][4]. ce sunt valorile elementelor array-ului id. astfel ca fiecare dimensiune este memorata ca un array diferit.0}.length. j++)a3[i][j] = new int[pRand(5)].Aceasta este de fapt o forma prescurtata pentru TipDeDate[] id=new TipDedate[]{listaDeInitializatori}. int[][] b=new int[2][]. ARRAY-URI MULTIDIMENSIONALE Array-urile multidimensionale sunt declarate prin adaugarea dimensiunilor. putem declara si construi array-uri multidimensionale de dimensiuni diferite.length. tipul elementelor trebuie sa fie acelasi.length=4.length. De exemplu.// prima linie are 3 coloane sau elemente b[1]=new int[4]. liste separate prin virgula.2. } for(int i=0. j<a3[i]. for(int j=0.6. De aceea. int[][] a={{1. iniţializate şi afişate diferite array-uri multidimesionale: import java. Numarul de elemente din lista de initializatori funrizeaza valoarea variabilei length pe variabila array asociata. j< a2[i]. elementele lui m nu vor fi memorate ca intr-o matrice ci liniar adica.abs(aleator.length. De exemplu.8}.k++) afiseaza("a2[” + i+"]["+j+"]["+k+"] = " + a2[i][j][k]). adică 2.*. De exemplu. j<a3[i]. {0. for(int i = 0. b. Alocarea memoriei necesare memorarii matricii m se face astfel: m=new[3][3]. i++){ a3[i] = new int[pRand(5)][]. 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. i++) for(int j=0.length furnizeaza numarul de linii ale lui b.util. i < a2. i<a3. elementele array-ul indicat prin variabila numere pot fi initializate de la declararea variabilei numere astfel: int[] numere={0.length. Următorul exemplu arată cum pot fi create.4. De exemplu. unde listaInitializatori este o multime de elemente de acelasi tip cu tipul array-ului. public class ArrayMultiDimensionale{ static Random aleator= new Random().length. Exemplu.nextInt())%mod. k++) afiseaza("a3["+i+ "]["+j+"]["+k+"]= " 23 . for(int i = 0.1}} memoreaza matricea unitate bidimensionala. //array 3-D cu vectori de lungime diferită pentru cele trei dimensiuni int[][][] a3 = new int[pRand(7)][][].length.

i < a4. arrayDest.out.i<a. } } Cautarea unei valori intr-un array folosind metoda Divide et Impera se realizeaza astfel: 24 . //array 3x2 de obiecte Integer Integer[][] a4={{new Integer(1). quickSort(0. i++) for(int j = 0. {new Integer(3). System.length.i++) System. if(p<j) quickSort(p. } afiseaza(). pozDest.print(a[i]+" ").random()*30).println(). j < a4[i]. afiseaza(). for(int i=0. new Integer(4)}. pozSursă. for(int i = 0.length.out.u).length. array-urile sunt folosite in probleme de sortare si de cautare. a[i]=nr.+a3[i][j][k]). }} LUCRUL CU ARRAY-URI Cand lucram cu array-uri putem folosi urmatoarea metodă statică a clasei System ce permite copierea unui număr de elemente consecutive ale unui array într-un alt array: static void arrraycopy(arraySursă. } public static void afiseaza(){ for(int i=0. new Integer(6)}}. public static void initializeaza(){ a=new int[20]. int u){ int i=p. sortarea elementelor unui array folosind metoda QuickSort se face astfel in Java: public class Ordonare{ static int[] a.j--. do{ while(a[i]<temp)i++. a[j]=t. j++) afiseaza("a4[" + i + "][" + j + "] = “ + a4[i][j]).19). } public static void quickSort(int p. int nr. if(i<u) quickSort(i.length. while(a[j]>temp)j--. a[i]=a[j].println(s). {new Integer(5). } if (i<=j) {i++. j=u. } static void afiseaza(String s){ System. nrElemente) In mod obisnuit. } public static void main(String[] args){ initializeaza().j). i<a.} }while (i<j). int temp=a[(p+u)/2].out. De exemplu.i++){ nr=(int)(Math. if (i<j){ int t=a[i]. new Integer(2)}.

out. j=t. public static void initializeaza(){ a=new int[20]. int nr. 25 . i=j.public class Cautare{ static int[] a.i++) System. } public static void afiseaza(){ for(int i=0. n1=n2. } apelul acestei metode schimba(a[i]. } afiseaza(). for(int i=0.out. while(p<u && val!=a[m]){ if(val<a[m]) u=m-1.random()*30). Integer n2=new Integer(j). De exemplu. } return a[m]==val. m=(p+u)/2.length-1.println("Nu a gasit="+nr). Elementele unui array de tip primitiv se transmit prin valoare. else System. int nr=(int)(Math.random()*30). u=a. metoda schimba() trebuie să fie scrisă astfel: public static int[] schimba(int i. int[] n=new int[2]. exact ca niste variabile simple. a[i]=nr. n2=n3.print(a[i]+" "). a[j]) nu ar fi realizat operatia respectiva. int j){ int t=i.i<a.println("A gasit="+nr). adica orice modificare efectuata asupra elementelor array-ului respectiv se memoreaza. daca in programul Ordonare anterior am fi avut metoda public static void schimba(int i. m=(p+u)/2. Pentru a realiza într-adevăr schimbarea două valori transmise prin valoare. atunci transferul se face prin referinta. } } ARRAY ÎN METODE Daca parametrul unei metode este o variabila array. } public static boolean cauta(int val){ int p=0.length. System.out.i++){ nr=(int)(Math.println().out. Integer n3=n1. int j){ Integer n1=new Integer(i).length. } public static void main(String[] args){ initializeaza(). else p=m+1. i<a. if(cauta(nr)) System.

afiseazaDate().println(personal[i]). când avem nevoie. 3000.u).00). i++) System. i++) personal[i]. } În metoda main. personal[0] = new Angajat(" ". 26 . public static void afiseazaDate() { System.println("\nLISTA PERSONAL"). // 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 afişăm de două ori date despre angajaţi.length.intValue(). am utilizat o variabilă array personal pentru a crea un array de doi angajaţi. return n. j=u. int u){ int i=p. afişăm date despre cei doi angajaţi. } public static void main(String[] args) { personal= new Angajat[2]. Apoi. n[1]=n2.00. metoda quickSort ar putea apela metoda schimba() astfel: public static void quickSort(int p. dintre care unul este Manager. int temp=a[(p+u)/2]. 2500. a[i]=n[0]. datorită relaţiei de generalizare/specializare dintre Angajat şi Manager. do{ while(a[i]<temp)i++. if(i<u) quickSort(i. ar trebui să scriem algoritmul de afişare într-o metoda statică şi s-o apelăm din metoda main. } if (i<=j) {i++..out.02).j).length.} n[0]=n1.} }while (i<j). if(p<j) quickSort(p..a[j]). i < personal. public class TestAngajati { static Angajat[] personal.j--. In acest caz. for (int i = 0. după care le mărim salariul cu 2% şi le afişăm din nou datele pentru a verifica creşterea salariului. while(a[j]>temp)j--. a[j]=n[1]. if (i<j){ int[] n=schimba(a[i]. " ").maresteSalariu(0. for (int i = 0. Putem să facem acest lucru. public static void main(String[] args) . afiseazaDate(). } Lucrul cu colectii de obiecte legate intre ele prin relatia de moştenire Presupunem ca vrem sa completam programul Angajaţi cu o clasă de test a cărei metodă main contine un array de doi angajaţi pentru a memora un angajat şi un manager..intValue(). i < personal. personal[1] = new Manager(" ".out.

Atunci. O subclasă a unei clase abstracte are obligaţia de a defini (implementa) metodele abstracte ale supraclasei. 2. constructorul unei clase abstracte nu poate fi apelat. În caz contrar. 1. dar are subclase care sunt clase concrete. Aşadar. subclasa respectivă trebuie să fie declarată abstractă şi este responsabilitatea subclaselor ei să implementeze metodele care au rămas abstracte din supraclasă. Înţelegerea modului în care se comportă obiectele clasei. adică declarate şi definite în clasa respectivă. metodele abstracte dintr-o clasa abstractă oferă o interfaţă comună tuturor subclaselor clasei abstracte. deoarece el diferă în funcţie de fiecare subclasă a clasei respective. Se inserează variabilele: sold de tip long şi proprietar de tip String. o clasă abstractă poate avea variabile ce pot fi moştenite de subclasele clasei respective. Un cont bancar poate fi creat vid. Aşadar. Cum comportamentul obiectelor unei clase este dat de mulţimea tuturor metodelor clasei. Care sunt operaţiile 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. Determinarea proprietăţilor clasei. În plus. CLASE ABSTRACTE O clasa abstractă este o clasă fără instanţe directe. care caracterizează obiectele clasei. numai cu numele proprietarului ⇒ ContBancar(numeProp: String) 27 . O clasă abstractă este declarată cu modificatorul abstract. rolul unei clase abstracte este de a facilita elaborările polimorfice asupra obiectelor subclaselor sale. De aceea. 3.1. public abstract int read() throws IOException. O clasă abstractă trebuie să conţină cel puţin o metodă abstractă adică metodă care nu defineşte algoritmul de implementare. putem declara variabile de tip o supraclasă abstractă care să conţină referinţe la obiectele subclaselor concrete ale clasei respective. chiar dacă o clasă abstractă conţine unul sau mai mulţi constructori. 5. dacă incercăm să-I apelăm vom avea eroare de compilare. Sintaxa declarării unei metode abstracte este următoarea: MetodaAbstractă::=[Modificator de vizibilitate] abstract Tip numeMetoda([parametri formali]). În schimb.5. Definirea modurilor in care vor fi create obiecte ContBancar.1 Dezvoltarea unei aplicatii pe obiecte Aplicaţia Cont bancar Se consideră definirea unei clase care descrie comportamentul unui cont bancar. Sintaxa declarării unei clase abstracte: ClasăAbstractă ::= [modificator de vizibilitate] abstract class Identificator{…} unde Identificator este numele clasei abstracte. Definirea numelui clasei: ContBancar. Fiind fără instanţe directe. adică pot fi instanţiate direct. o clasă abstractă poate avea metode concrete. Exemple: abstract void metoda(). atunci obiectele unei clase abstracte au un comportament parţial definit.

Fiecare tranzacţie efectuată are un cost constant exprimat în euro. restul tranzacţiilor trebuie să fie plătit. suma : Long. Costul unei tranzacţii este constant. } public ContBancar(long sold. Acest număr este memorat în constanta NR_TRANZACTII_GRATUITE. ntg : Integer. După ce am analizat problema. public ContBancar(String numeProp){ proprietar=numeProp. Un cont de economii este un cont bancar caracterizat de o dobândă ce poate fi vizualizată la cerere. rata : Double) ContEconomii(prop : String. proprietar=numeProp. costul tranzacţiilor va fi extras din cont şi numărul tranzacţiilor porneşte de la zero. sold : Long. clasa ConBancar este o clasă abstractă cu metodele abstracte depune şi scoate. 28 . Această operaţie este realizată de metoda aplicăDobânda(). numeProp:String) Un cont bancar este de două tipuri: cont de economii sau cont curent. Tinând cont de această cerinţă. ntg : Integer. ct : Integer) ContCurent(prop : String. Dobânda este utilizată la anumite intervale de timp. Orice persoană care vrea să-şi deschidă un cont bancar trebuie să specifice tipul contului: de economii sau curent. Un cont curent este un cont bancar caracterizat de un număr de operaţii sau tranzacţii efectuate asupra contului într-o anumită perioadă de timp. ct : Integer) descarcaCheltuieli() Implementarea în Java public abstract class ContBancar{ protected long sold.Un cont bancar poate fi creat iniţializând soldul şi numele proprietarului ⇒ ContBancar(sold: Long sold. } public abstract void depune(long suma). când trebuie să fie calculată şi adăugată la soldul curent. obţinem următoarea diagramă de clase în UML: ContBancar sold : Long proprietar : String ContBancar(numeProp : String) ContBancar(sold : Long. iniţializată la crearea contului curent. este iniţializat la crearea unui cont curent şi memorat în constanta COST_TRANZACTIE. La anumite intervale de timp. numeProp : String) depune(suma : Long) scoate(suma : Long) getSold() : Long getProprietar() : String ContEconomii rataDobanda : Double ContEconomii(prop : String.sold=sold. rata : Double) aplicaDobanda() ContCurent nrTranzactii : Integer NR_TRANZACTII_GRATIS : Integer COST_TRANZACTII : Integer ContCurent(prop : String. protected String proprietar. Un cont curent are un număr de tranzacţii gratuite. String numeProp){ this. După efectuarea acestui număr de tranzacţii.

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

dacă suma este scoasă înainte de scadenţă.println(ce). un tip particular de ContEconomii. } } private void descarcaCheltuieli(){ if (nrTranzactii>NR_TRANZACTII_GRATIS){ scoate((nrTranzactii-NR_TRANZACTII_GRATIS)*COST_TRANZACTIE). În acest cont.println(cc). nu există nici o penalizare pentru operaţia de extragere. ce. Apoi. să se modifice clasa TestContBancar.println(ce).depune(15000). cc. nrTranzactii++. probabil în schimbul unei dobânzi mai mari. ContCurent cc=new ContCurent("Popescu". În schimb. Să se îmbogăţească ierarhia clasei ContBancar cu o nouă clasă ContDepozitTemporar. 5.scoate(2000). } } Exerciţiu. } } public String toString(){ return super.out. cost tranzactie: "+COST_TRANZACTIE.out. cc. titularul se obligă să lase banii un anumit număr de luni. nrTranzactii=0. executăm 2-3 tranzacţii pentru fiecare cont şi vizualizăm situaţia.depune(5000). 0.15). modificând un cont de economii într-un cont de perioadă limitată (utilizaţi polimorfismul metodelor).10000. System.scoate(12000). Odată ce s-a îndeplinit termenul de scadenţă a contului. 30 . ce. ea va fi eliberată fără dobândă. public class TestContBancar{ public static void main(String[] args){ ContEconomii ce=new ContEconomii("Ionescu".toString()+". 2000). 20000. System. System. } } Pentru a testa ierarhia de clase construită vom scrie clasa TestContBancar care crează un cont de economii şi un cont curent. la început şi după efectuarea tranzacţiilor.if(s<=sold){ sold-=s. System.out.println(cc).out. numar de tranzactii gratis: "+ NR_TRANZACTII_GRATIS+".

public in compareTo(Object o) { return (this. // date-membru [Modificator] SemnaturaMetoda. Fiecare clasă trebuie să implementeze în mod personalizat metoda: public class ContEconomii implements Comparable { .dobanda < o.compareTo(cont304)>0) then . O interfaţă este o colecţie de comportamente abstracte care pot fi implementate de o clasă pentru adăugarea unui comportament care nu este furnizat de superclasa clasei respective. numai că aceste tipuri. . clasa Angajat va implementa interfaţa Comparable care are o metodă compareTo(Object). O interfaţă poate moşteni de la o altă interfaţă. . } } Atunci.{ CorpClasa } O clasă care doreşte să implementeze o interfaţă. Cele două clase implementează interfaţa Comparable care are o metodă compareTo(Object). Clasa trebuie să implementeze în mod personalizat metoda: public class Angajat implements Comparable { . “Să se ordoneze angajaţii unei întreprinderi după salariu pentru a putea face o statistică legată de taxele de plătit. . Exemplu. . ca şi clasele.. Declaraţia unei interfeţe: [Modificator] interface Identificator [extends NumeInterfata.. . . . Interfaţa în Java este o entitate distinctă de clase şi array-uri. Ordonarea se poate face în mod personalizat. Implementarea unei interfeţe O clasă care decide să implementeze o interfaţă trebuie să declare acest lucru în definiţie. .dobanda > o. Interfeţele în Java trebuie să fie declarate. O interfaţă poate conţine şi membri-date constante.} Pentru fiecare declaraţie de interfaţă compilatorul crează un fişier . prezintă numai servicii.. ContEconomii sau Angajat au obiecte care nu sunt comparabile.class. 31 .. .] { Tip Identificator= . se poate scrie simplu. Interfeţele reprezintă. . INTERFETE Conceptul de interfaţă Presupunem că avem următoarele două probleme: 1. public interface Comparable {public int compareTo (Comparable b)..dobanda)?1:(this. . având două conturi cont122 şi cont304: if(cont122. // metode abstracte } Exemplu. trebuie să implementeze toate metodele interfeţei. Dacă vrem sa ordonăm angajaţii unei întreprinderi după salariu pentru a putea face o statistică legată de taxele de plătit. “Să se ordoneze conturile de economii după dobânda pentru a decide care dintre ele este mai bun pentru a depune o sumă de bani disponbila.” Pentru rezolvarea acestor probleme avem două soluţii: 1. . pentru fiecare clasă.6. în loc să prezinte date+servicii. Interfeţe în Java Interfaţă = Listă de metode publice şi abstracte.dobanda)?-1:0. . 2. tipuri de date. Sintaxa: class Identificator implements NumeInterfata.” 2.

la execuţie. Vector v = new Vector(). . } .getSalariu()). ). Variabilele interfaţă sunt în special utilizate ca parametri în metode pentru a permite upcasting al obiectelor ce provin din clase diferite între ele. în interiorul unei astfel de metode putem invoca orice metodă a interfeţei. protected native Object clone() //clone restituie un Object generic throws CloneNotSupportedException. public interface Serializable {}.util. public class OperatiiSpecificatiiProdus implements OperatiiObiecte{ private PrintWriter pw. String nume = s. . În acest caz: 2.io. Variabile-interfaţă Intr-un program se pot declara variabile de tip interfaţă.1. . public OperatiiSpecificatiiProdus(){ try{ 32 . . transmiţând unui alt apel un obiect al unei alte clase care implementează interfaţa se detrmină o execuţie care poate fi complet diferită de prima. rezultatul v2 = (Vector) v. . 2.io. } O clasă poate implementa mai multe interfeţe. .*.compareTo(d) < 0) . //Pentru a-l putea utiliza. .4. .2. import java. . Vector v2. 2. .public int compareTo(Object o) { return (int)(getSalariu() – ((Angajat)o). la invocarea unei metode pentru acel obiect determină executarea unei implementări particulare a metodei ce aparţine clasei obiectului. se poate transmite ca argument orice obiect al unei clase care implementează interfaţa 2. .compareTo(d) < 0) . public Object citesteObiect(String cheie). // Eroare!! Cum utilizăm interfeţele 1.3. s = new Angajat(.). Exemplu.clone(). public interface OperatiiObiecte{ public void scrieObiect(Object o). // va fi convertit la tipul dorit Interfaţa Serializable nu are metode: package java. //Angajat promovat ca tip Comparable O variabilă interfaţă poate fi accesată numai cu metodele interfeţei. . Utilizaţi o interfaţă pentru a separa un comportament care este implementat în orice clasefurnizor ale claselor client care le utilizează. Utilizaţi interfeţele ca parametri ai metodelor. if (s. Angajat d = new Angajat(. ca de exemplu: Comparable s. O variabilă interfaţă poate memora referinţa la o instanţă a oricărei clase care implementează acea interfaţă.*. . O interfaţă poate fi implementată de mai multe clase. la fel cum face şi o variabilă a unei clase. if (s.getNume(). Interfeţe Java standard Interfaţa Cloneable trebuie să fie implementată de toate clasele care se clonează. . } import java. . . O variabilă interfaţă poate participa în calcule la fel ca orice variabilă referinţă. 2.

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

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

Continuând aplicaţia GestiuneAngajaţi din ultimele două cursuri. instanţierea clasei interner depinde de modificatorul de vizibilitate a acesteia din urmă. vechime=v. System. long salariu. clasa externă trebuie să conţină 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ă. Orice obiect al unei clase interne este legat automat de un obiect din clasa externă din care face parte şi din acest motiv.NumeClasaInterna. presupunem că clasa Manager are o clasă internă numită Secretara: public class Manager extends Angajat{ private int vechime. O clasă internă privată furnizează o modalitate de a ascunde informaţii despre implementarea realizată de clasa externă. salariu). } } Dintr-o clasă externă putem crea fără probleme obiecte ale oricărei clase internă a sa. CLASE INTERNE DEFINIREA CLASELOR INTERNE Într-un program Java este posibil să plasăm o definiţie a unei clase în spaţiul de nume al altei clase.Secretara s=m. care este clasă externă pentru aceasta.7. } Dacă clasa internă este privată şi vrem să dăm acces clienţilor clasei externe la obiectele primei clase. putem crea obiecte din această clasă. 7). Clasele interne ne permit să grupăm clasele care sunt conectate logic între ele şi să controlăm vizibilitatea acestora. dacă clasa internă oferă acces. 500. Exemplu. cu ajutorul unei variabile instanţă de tip clasa externă şi tipul noii variabile instanţă este un tip compus: NumeClasaExterna. } String getNume(){ return nume. ca în exemplul următor: public static void main(String[] args){//in clasa Manager Manager m=new Manager("Ionescu". } public class Secretara{ private String nume.println(s. spunem că am definit clasa internă celei de-a doua clase. De exemplu. public Manager(String nume. În acest caz.getNume()). în clasa Secretara putem defini următoarea metodă: 35 . acesta poate accesa orice variabilă şi pot apela orice metodă (indiferent ce modificator de vizibilitate au) ale obiectului înconjurător.new Secretara("Maria").out. Din afara clasei externe. int v){ super(nume.nume=nume. Astfel. public Secretara(String nume){ this. Manager.

toate variabilele.} Clasele interne pot fi definite într-o metodă sau chiar într-un bloc arbitrar clasei din care fac parte. } CLASE INTERNE STATICE O clasă internă statică se declară folosind modificatorul static: 36 .} }. putem defini clasa SecretaraE în corpul metodei obtineObiectSecretara(String): public Secretara obtineObiectSecretara(String nume){ class SecretaraE extends Secretara{ private String nume. } Mai mult.nume=nume.public int getVechime(){return vechime.println(“vechime manager= ”+ s. } public String getNume(){ return n. Într-o clasă internă putem scrie o metodă care să returneze o referinţă la obiectul înconjurător. De exemplu.este o decizie de proiectare sau chiar de implementare. } }. { nume=n.} care poate fi apelată din metoda main: System.this. o clasă internă definită în corpul unei metode poate fi facută clasă anonimă în următoarele condiţii: . public String getNume(){return n.putem declara variabile instanţă şi le putem iniţializa cu valorile transmise prin parametrii metodei. Acest obiect poate fi folosit pentru a acesa. private SecretaraE(String nume){ this. neprivate ale clasei externe: public Manager getManager(){return Manager.} }//clasa interna return new SecretaraE(nume). numai că aceştia trebuie să fie declaraţi finali: public Secretara obtineObiectSecretara(final String n){ return new Secretara(){ private String nume=n. } public String getNume(){return nume.clasa internă extinde o clasă abstractă sau implementează o interfaţă şi astfel putem crea şi returna o referinţă la aceasta .out. deoarece clasa externă rezolvă o problemă mai grea şi avem nevoie de o clasă ajutătoare pe care să o folosim local. O astfel de decizie apare din două motive: . } Iniţializarea variabilelor instanţă ale clasei interne poate fi facută într-un bloc de iniţializare: public Secretara obtineObiectSecretara(final String n){ return new Secretara(){ private String nume. respectiv metodele.getVechime()). respectiv apela.clasa internă anonimă nu defineşte un constructor propriu .

respectiv apela nici o variabilă. De exp. Mai departe.} In metoda main.nume=nume. De exemplu. putem declara următoarea clasa abstractă: abstract class Secretara{ public abstract String getNume().getNume()). } }//clasa interna Clasele interne statice îndeplinesc următoarele condiţii: 1. Manager. clasele interne statice pot fi incorporate în interfeţe: interface ISecretara{ public String getNume(). } CLASE INTERNE ŞI MOŞTENIREA Un motiv pentru care putem folosi clase interne este de a obţine în Java moştenirea multiplă: o clasă internă extinde o clasă concretă sau abstractă sau implementează o interfaţă. public SecretaraEI(String nume){ this. private SecretaraE(String nume){ this.SecretaraEI("Maria")..println(s. de exemplu. În schimb. System. putem declara clasa internă SecretaraE privată şi atunci este o clasă ascunsă oricărui client al clasei externe.out. Fiind statică. } public String getNume(){ return nume..private static class SecretaraE extends Secretara{//in clasa Manager private String nume. private class SecretaraE extends Secretara{ . Pentru a crea un obiect al clasei interne statice nu avem nevoie de un obiect al clasei externe 2..nume=nume. private SecretaraE(String nume) } public Secretara obtineObiectSecretara(String nume){. } }//clasa interna }//interfata public static void main(String[] args){//din Manager ISecretara s=new ISecretara.getNume()). } public String getNume(){ return nume.. respectiv metodă instanţă a clasei înconjurătoare.println(s. se poate obţine o referinţă la clasa de bază Secretara (sau la interfaţa implementată) care furnizează funcţionalitatea declarată. numai variabile şi metode statice. putem crea în metoda main un obiect al clasei SecretaraE astfel: Secretara s=new SecretaraE("Maria"). } În acest caz. dintr-un obiect al unei astfel de clase nu putem accesa un obiect al clasei înconjurătoare şi astfel nu putem accesa.out. putem obţine un obiect din clasa SecretaraE astfel: 37 . static class SecretaraEI implements ISecretara{ private String nume.//in main System.

Acţiunea depinde de tipul evenimentului apărut.//in main O clasă internă poate extinde orice clasă concretă sau abstractă.obtineObiectSecretara(m.out.Secretara s=m. Mai mult.this). long salariu.obtineObiectSecretara("Maria"). } public class SecretaraE extends Manager. 500.obtineObiectSecretara("Maria").Secretara s=m.SecretaraE s=m. System. } public static void main(String[] args){ ManagerE m=new ManagerE("Ionescu". Un eveniment este o entitate conceptuală care spune că ceva are loc în timp şi spaţiu şi are consecinţe asupra unei aplicaţii.super(nume). String nume){ m. System. Cu acest constructor putem apela constructorul supraclasei extinse: public class ManagerE extends Manager{ public ManagerE(String nume. salariu. De exemplu.evenimente externe.Secretara{ public SecretaraE(Manager m. } } În acest caz putem introduce o nouă metodă (overloaded cu cea moştenită) care să returneze un obiect al subclasei interne SecretaraE: public SecretaraE obtineObiectSecretara(ManagerE m. 7).getNume()). Cu alte cuvinte.super(nume). în momentul în care apare un eveniment. int v){ super(nume.Secretara{ public SecretaraE(String nume){ (ManagerE. Evenimentele sunt în general de două tipuri: . aplicaţia noastră trebuie să execute o acţiune.out. } UTILIZAREA CLASELOR INTERNE ÎN APLICAŢII OO Clasele interne au fost introduse pentru a trata evenimentele gestionate de aplicaţiile programate orientat spre obiecte. 500. Manager. } public class SecretaraE extends Manager.println(s. int v){ super(nume. salariu.nume).getNume()). o clasă A internă clasei B poate extinde o clasă internă a supraclasei lui B. v). 7). cele generate de utilizator în interacţiunea sa cu aplicaţia noastră şi 38 . clasa ManagerE extinde clasa Manager: public class ManagerE extends Manager{ public ManagerE(String nume. v). } } O altă soluţie ar fi ca constructorul clasei interne SecretaraE să conţină o variabilă referinţă la clasa înconjurătoare a clasei externe extinsă.println(s. ManagerE."Maria"). long salariu. } } public static void main(String[] args){ Manager m=new ManagerE("Ionescu". String nume){ return new SecretaraE(m.

} public abstract void executaActiune(). e=null.currentTimeMillis()>=moment.executaActiune(). System. Aşadar. cele generate în interiorul aplicaţiei.} public String getCuloare(){return culoare. int culoare){ super(timp).out. } public void gestioneaza(){ while(true) if (e.s=s. public GestorSemafor(Semafor s){ this.aAparut()){ e. public void setCuloare(String c){culoare=c. public SchimbareCuloare(long timp. Vom avea clasa Semafor care conţine o variabilă instanţă privată culoare. toate evenimentele tratate de clasa GestorSemafor sunt de acelaşi tip SchimbareCuloare: public class GestorSemafor extends Controller{ private Semafor s. } şi un gestor generic de evenimente: public class Controller{ private Eveniment e.culoare=culoare. this. ce reprezintă culoarea curentă aratată de semafor: public class Semafor{ private String culoare. } } } Exemplu. Să scriem de exemplu o aplicaţie care simulează funcţionarea unui semafor de circulaţie.- evenimente interne.println(e. public Eveniment(long mT){ moment=mT. Atunci putem defini o clasă abstractă Eveniment ca o clasă generică de evenimente: public abstract class Eveniment{ private long moment. public void setEveniment(Eveniment e){ this.e=e. } public class SchimbareCuloare extends Eveniment{ int culoare. } 39 . } public boolean aAparut(){ return System.} } Semaforul este controlat de clasa GestorSemafor care extinde clasa Controller şi tratează fiecare eveniment produs de schimbarea culorii la semafor. break. public abstract String descriere().descriere()).

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().new SchimbareCuloare(timp+2000*i+1000.break. i++){ long timp=System. } } } 40 .setCuloare("rosu").gestioneaza(). } } public String descriere(){ return "Culoarea aratata de semafor este "+s. for (int i=1. gs.setCuloare("galben"). case 3: s.new SchimbareCuloare(timp+3000*i+2000.setEveniment(gs. GestorSemafor gs=new GestorSemafor(s). gs. i<=10.public void executaActiune(){ switch(culoare){ case 1: s.break.setEveniment(gs.gestioneaza(). gs. 2)). gs. } } } Observăm că clasa SchimbareCuloare este o clasă internă şi este o subclasă a clasei Eveniment. gs. gs.setEveniment(gs.currentTimeMillis(). case 2: s.setCuloare("verde"). 3)). 1)).new SchimbareCuloare(timp+1000*i.gestioneaza().getCuloare().

DataInputStream. INPUT/OUTPUT ÎN JAVA Pachetul java. Clase de fluxuri de ieşire: OutputStream. Clasa StreamTokenizer permite convertirea unui flux de intrare a datelor într-un flux de token-i şi conţine metode pentru definirea sintaxei token-ilor. BufferedOutputStream.8. FileInputStream şi StringBufferInputStream. FileReader şi StringReader sunt derivate din clasa abstractă Reader. BufferedWriter. Clase de citire a caracterelor Unicode: Reader.io Furnizează suport pentru citirea şi scrierea datelor de la şi la dispozitive diferite. 4. Clase de scriere a caracterelor în Unicode: Writer.clase de fluxuri de intrare şi clase de citire .clase de fluxuri de ieşire şi clase de scriere . FileOutputStream. Sunt derivate din clasa OutputStream. Clase de fluxuri de octeţi: BufferedInputStream. Derivate din clasa abstractă InputStream. 2. BufferedReader. PrintStream şi StringBufferOutputStream. Claselor FileInputStream şi FileOutputStream se adaugă alte două clase destinate gestiunii fişierelor: File şi RandomAccessFile. 41 . Conţine 4 categorii de clase: . Sunt derivate de clasa abstractă Writer.clasa StreamTokenizer 1. 3. FileWriter şi PrintWriter.clase de gestiune a fişierelor .

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 .

Dacă b este mai mic decât numărul de caractere citite. int read(byte[] b) throws IOEXception int read(byte[] b. sintaxa metodelor read() a fost modificată astfel: Semnătura metodei int read() throws IOEXception Semnificaţie –Valoarea returnată citeşte un caracter de pe fluxul de intrare şi returnează codul său Unicode. citeşte octeţi de pe fluxul de intrare şi îi memorează în array-ul b. int poz. Metodele clasei InputStream sunt prezentate în următorul tabel: Semnătura metodei abstract int read() throws IOEXception Semnificaţie –Valoarea returnată returnează un octet citit de pe fluxul de intrare. Metoda returnează numărul de caractere citite efectiv. ignoră maxim n octeţi din fluxul de intrare şi întoarce numărul de octeţi cu care s-a avansat in flux. Dacă se detectează sfârşitul fluxului atunci metoda intoarce –1. se lansează o exceptie. se lansează o exceptie. de la poziţia poz. această instanţă reprezintă fluxul standard de intrare (tastatura). Metoda returnează numărul de octeţi citiţi efectiv.in = variabilă statică a clasei System care memorează o instanţă a clasei InputStream. se lansează o exceptie. întoarce true dacă fluxul suportă operaţia de marcare şi revenire la poziţia marcată.setIn(fi).setIn(InputStream) astfel: FileInputStream fi = new FileInputStream(“input. Metoda returnează numărul de caractere citite efectiv. De aceea. se lansează o exceptie.txt”).Clasa InputStream InputStream = clasă abstractă din care derivează toate clasele fluxului de intrare. returnează numărul de octeţi disponibili pentru citire fără blocare. Dacă b este mai mic decât numărul de octeţi citiţi. citeşte caractere de pe fluxul de intrare şi îi memorează în array-ul b. int read(char[] b) throws IOEXception abstract int read(char[] b. specializată în citirea caracterelor. marchează poziţia poz în flux pentru ca ulterior să se poată reveni la ea. Dacă se detectează sfârşitul fluxului atunci metoda intoarce –1. De obicei. închide fluxul de intrare şi eliberează resursa alocată. 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 Aceeaşi structură are clasa abstractă Reader. dar poate fi setată cu System. System. int poz. Metoda returnează numărul de octeţi citiţi efectiv. Dacă b este mai mic decât numărul de octeţi citiţi. Nu toate fluxurile de intrare oferă această operaţie. Crearea unui flux de date de intrare 43 . citeşte maxim nr octeţi de pe fluxul de intrare şi îi memorează în array-ul b. Dacă b este mai mic decât numărul de caractere citite. repoziţionează fluxul la ultima poziţie marcată. de la poziţia poz. int nr) throws IOEXception System. citeşte maxim nr caractere de pe fluxul de intrare şi îi memorează în array-ul b.

Int.funcţionează ca un InputStream. FileInputStream (String nume): - execută operaţii de intrare simple asupra fişierelor (pentru operaţii mai avansate se utilizează RandomAccessFile).} return c. BufferedInputStream (InputStream in): .când nu mai sunt date disponibile. try{ c=(char)System. .getMessage()). Float sau Double) care citesc un număr de octeţi din fluxul de intrare necesar pentru a obţine o valoare de tip primitiv specificat în numele metodei. long etc.in. Se indică locul din care vor fi citite datele.//nu se citeşte caracterul generat de apăsarea lui Enter }catch(IOException e){System.construieşte fluxul şi cu un obiect File sau FileDescriptor.). Caracteristicile citirii: . DataInputStream (InputStream in): - utilizată pentru citirea datelor primitive (int. metoda readInt() citeşte patru octeţi din fluxul de intrare şi întoarce o valoare de tip int. int markpos şi int marklimit. int pos.Crearea unui flux de date de intrare respectă modelul pipeline Unix: face parte dintr-o sursă de date cu interfaţa InputStream şi se crează succesiv cu filtri ai aceleaşi interfeţe. Long.out. la metodele furnizate de InputStream se adaugă metodele interfeţei DataInput readxxx() (xxx = Boolean. dar operează asupra unui fişier.in. instanţa clasei se blochează în aşteptarea ca datele să devină disponibile.furnizează un flux de intrare buffer-izat permiţând astfel o citire mult mai rapidă. - 44 . De exemplu. PushBackInputStream (InputStream in) . .funcţionează ca InputStream. Byte. . .println(e. . } Clase de flux de octeţi de intrare 1.are o metodă unread(int ch). Se crează o instanţă a unei clase de flux de intrare. char. 2. Char. int count. Short. moşteneşte atât interfaţa DataInput cât şi clasa abstractă FilterInputStream. UnsignedShort. utile dacă se extinde clasa BufferedStream.este un flux continuu. .construieşte un flux cu un caracter lookahead. 3. Metoda urmatoare citeşte un caracter de la tastatură şi-l returnează: public char citeste(){ char c='0'.are unele variabile membru: byte buf[]. 4. FileInputStream BufferedInputStream DataInputStream byte int File File system (Sursă date) Bytes Buffer de bytes Date formatate char float long Memoria Exemplu.include numai metodele furnizate de InputStream. System.skip(2). Pentru a citi date în Java procedura este întotdeauna aceeaşi: 1.read(). 2. .

close(). } } } Clasa OutputStream OutputStream = clasă abstractă din care derivează toate clasele fluxului de ieşire.txt")). FileReader.in)). } catch(EOFException e){ System. //3. scrie pe fluxul de ieşire octeţii din array-ul b scrie nr octeţi pe fluxul de ieşire începând de la poziţia poz a array-ului b. StringReader. while(true) System.println("Exceptie IO").readByte()).out. while((s1 = in2. //2.print((char)c).read() ) != -1) System. PushBackReader. in1. in3. Următorul exemplu arată mai multe modalitaţi de a face o citire folosind clasele derivate din InputStream şi Reader: import java.out.*.println("Am ajuns la sfarsitul fisierului"). } catch (IOException e){ System. In plus.io.close().readLine())!= null) s2 += s1 + "\n". int poz. s2 = new String().println("Fisier inexistent"). } catch (FileNotFoundException e){ System.out. Citirea din memorie formatata DataInputStream in4 = new DataInputStream( new FileInputStream("intrare. Semnătura metodelor write() se modifică şi apar două forme noi ale acestei metode: Semnătura metodei Semnificaţie –Valoarea returnată void write(int IOEXception void write(char[] n) b) throws scrie valoarea lui n pe fluxul de ieşire.print((char)in4. Citirea unei linii de la tastatura BufferedReader in1 = new BufferedReader( new InputStreamReader(System. String s=in1.Clasa abstractă Reader are subclase asemănătoare cu cele ale clasei abstracte InputStream: BufferedReader. int nr) throws IOEXception void flush() throws IOException void close() throws IOException Semnificaţie –Valoarea returnată scrie valoarea lui n pe fluxul de ieşire. int c. există clasa InputStreamReader care face legătura dintre o clasa de tip InputSream şi un Reader. Clasa Writer Clasa Writer specializată în scrierea fluxurilor de caractere are o ierarhie similară cu ierarhia lui OutputStream. in2.readLine().close().out. public class FluxDeIntrareIesire{ public static void main(String[] args) { try { //1. BufferedReader are o metoda String readLine(). String s1. Citirea dintr-un fisier BufferedReader in2 = new BufferedReader( new FileReader("intrare. goleşte fluxul de ieşire închide fluxul de intrare şi eliberează resursa alocată. Citirea din memorie StringReader in3 = new StringReader(s2). Metodele clasei OutputStream sunt prezentate în următorul tabel: Semnătura metodei abstract void write(int n) throws IOEXception void write(byte[] b) throws IOEXception void write(byte[] b. throws scrie pe fluxul de ieşire caracterele din array-ul b 45 .out. //4.txt")). while((c = in3.

altele decât cele furnizate de Write. are două variabile membru utile: byte buf[] şi int count. public void write(String str) scrie şirul str pe fluxul de ieşire. 46 . metodele sale. System. long. poz. boolean.setOut(OutputStream): FileOutputStream fs = new FileOutputStream(“log. String.txt”). Se indică locul unde vor fi scrise datele. dar operează pe fişiere. - 3. FileWriter execută operaţii simple de ieşire de caractere pe fişiere (pentru operaţii mai avansate pe fişiere se utilizează RandomAccessFile). throws IOException public void write(String str. 2. BufferedWriter derivează din Writer. . nu conţine alte metode în afară de cele furnizate de Writer. Este setată cu System. la destinaţie. deoarece obiectul obţinut are caracteristicile dorite: buffer-izat.out = variabilă statică a clasei System care memorează o instanţă a clasei PrintStream ce reprezintă de obicei ecranul monitorului. int nr) throws IOEXception poziţia poz a array-ului b. int nr) throws IOException System.setOut(new printStream(fs)). împreună cu numărul liniei curente.Semnătura metodei Semnificaţie –Valoarea returnată IOEXception abstract void write(char[] b. un obiect File sau un FileDescriptor. Scrierea cu clasele Output Stream şi Writer Primul exemplu din această subsecţiune arată cum se poate determina numărul de linii ale unui fişier şi scrierea fiecărei linii citite într-un alt fişier. true). int.este un flux continuu. char. PrintWriter out= PrintWriter(new FileWriter(“personale. int scrie nr caractere pe fluxul de ieşire începând de la poz. char[]. Caracteristicile scrierii: . Instanţa se poate crea plecând de la destinaţie şi compunând fluxul din obiecte-flux încuibate. int scrie pe fluxul de ieşire subşirul de lungime nr pe care-l extrage de la poziţia poz a şirului str. - PrintWriter derivează din Writer afişează date-text (şiruri sau numere). funcţionează ca Write. include: print(tip) şi println(tip) unde tip ia una din valorile: Object. float şi double. 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 ieşire 1.instanţa clasei de flux trimite date cât timp acestea sunt disponibile. Procedura de scriere a datelor cu o clasă de fluxuri de ieşire este întotdeauna aceeaşi: 1. constructorul are ca argument un obiect Writer. furnizează un flux de ieşire buffer-izat. Se crează o instanţă a clasei fluxului de ieşire specificând fluxul final. 2. construieşte un obiect numai cu un şir.txt”). în stare să scrie date primitive etc.

} catch(IOException ioe){System. out.readDouble()). System.close().out.readChar(). } } } 47 . } in.txt"))). if(i<s. int i=0.println("Eroare de intrare/iesire").writeDouble(3.getLineNumber()+ " "+ s).writeBytes("Valoarea lui PI"). boolean more=true.i<size. if(c==0) more=false.} Clasa următoare furnizează două metode care citesc.println(inbr. BufferedReader inbr = new BufferedReader(new InputStreamReader(in)).txt"))).println("Sfarsitul fluxului"). PrintWriter out=new PrintWriter(new BufferedWriter( new FileWriter("iesire.close().writeChar(c).txt")). DataOutput out) throws IOException{ for(int i=0. DataInput in)throws IOException{ StringBuffer buffer=new StringBuffer(size).Observaţie. int size. while((s = lnr. try{ LineNumberReader lnr = new LineNumberReader(new FileReader("intrare.} Următorul exemplu arată cum scriem şi citim date formatate într-un/dintr-un fişier. return buffer.i++){ char c=0.out. lnr. subclasă a lui BufferedReader. Adică vom folosi o instanţă a clasei LineNumberReader. out.*.println("Sfarsitul fisierului").println("Linia " +lnr. out. }catch(EOFException e){System. public class DataIO{ public static String citesteSirFix(int size.skipBytes(2*(size-i)).out.14159).close(). Pentru a afla numărul liniei curente vom folosi un cititor buffer-izat ce păstrează numărul liniei citite.14159 şi şirul “Valoarea lui PI”: try{ DataOutputStream out=new DataOutputStream(new BufferedOutputStream( new FileOutputStream("Data.charAt(i).println("Eroare de intrare/iesire"). else buffer.toString(). } public static void scrieSirFix(String s.out.io. out. String s="".readLine()) != null) out.} catch(IOException ioe){System. System.length()) c=s. i++. respectiv scriu date formatate pe linii de lungime fixă: import java.append(c).out. }catch(EOFException e) {System. while(more&& i<size){ char c=in. DataInputStream in = new DataInputStream(new BufferedInputStream( new FileInputStream("Data.txt"))).println(in. out.readLine()).out. Vom folosi instanţe ale claselor DataOutputStream şi DataInputStream pentru a scrie numărul 3.

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

“\\” pentru sistemele Windows .getMessage()). Calea poate fi absolută sau relativă la directorul în care se găsesc class-urile programului. String nume)//calea directorului părinte este dat ca un obiect File Metodele mai importante ale clasei File sunt prezentate în următorul tabel: Semnătura 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) Semnificaţie –Valoarea returnată returnează numele fişierului sau directorului curent returnează calea unde se află fişierul sau directorul curent pe disc returnează calea absolută unde se află fişierul sau directorul curent pe disc întoarce directorul părinte a directorului sau în care se găseşte fişierul curent returnează true dacă fişierul indicat in constructor există pe disc. returnează true dacă fişierul respectiv poate fi modificat returnează true dacă fişierul respectiv poate fi citit returnează true dacă şirul indicat ca fişier există pe disc şi este un fişier returnează true dacă şirul indicat ca director există pe disc şi este un director returnează data şi ora ultimei modificări returnează mărimea fişierului. precum si locaţiilor unde se găsesc acestea într-un sistem de fişiere.readData(in). String nume)//crează un obiect File ce conţine separat numele fişierului şi calea directorului în care se află fişierul File(File dir. întoarce într-un array de şiruri numele fişierelor şi directoarelor din directorul curent care îndeplinesc criteriul filtru 49 . Locaţia unui fişier reprezintă calea în sistemul de fişiere unde este memorat acesta. Separatorul unei căi depinde de sistemul de operare pe care rulează programul si anume: . respectiv ca un caracter.} Clasa File Clasa File prezintă o vedere abstractă a numelor fişierelor şi a directoarelor.out. Acesta este memorat în constantele String separator şi char separatorChar. } } } } catch(IOException e){System. System. Constructori: File(String cale)//crează un obiect File ce contine o cale absolută sau relativă şi care poate conţine numele fişierului File(String cale.println(an[i]).an[i]. văzut ca un String.“/” pentru sistemele Unix.out.println(e. în biţi returnează true dacă a fost creat directorul specificat in cale returnează true dacă au fost create directoarele specificate in cale redenumeşte fişierul cu curent cu numele dest şi returnează true şterge fişierul sau directorul curent întoarce într-un array de şiruri numele fişierelor şi directoarelor din directorul curent.

isFile()) buffer.append("este un director\r\n").append("este un fisier\r\n").println("Dati numele fisierului/directorului"). scrie(analizeaza(citeste())).append("calea absoluta "+nume.length()-1) sufix=nume. if(nume.De exemplu.append("data ultimei modificari "+nume. PrintWriter pw.append(nume.*.').equals("java").append("este o cale absoluta\r\n").java)". int i=nume. buffer. return sufix. data ultimei modificări. De exemplu. public class Fisier{ BufferedReader br.append("nu este o cale absoluta\r\n"). } public String analizeaza(String sir){ File nume=new File(sir). cum ar fi: dacă este fişier sau director. public Fisier(){ try{ br=new BufferedReader(new InputStreamReader(System.getParent()+"\r\n"). if(nume. else buffer.append("calea "+nume.readLine(). locaţia sa pe disc. buffer. } public String getDescription(){ return "fisiere java(*. StringBuffer buffer=new StringBuffer(). String nume){ String sufix="".append("lungimea "+nume. true). if(i>0 && i<nume.txt").getName()+" exista\r\n").isAbsolute())buffer.lastModified()+"\r\n").length()+"\r\n"). } } Următorul exemplu citeşte numele unui fişier/director de la tastatură şi-l scrie informaţii despre el. etc. buffer. următoarea clasa filtreaza fişierele dintr-un director si le acceptă numai pe cele care sunt programe Java: import java.getAbsolutePath()+"\r\n").lastIndexOf('.io. buffer.in)).exists()){ buffer.isDirectory())buffer. pw=new PrintWriter(new FileWriter("analiza. if(nume.substring(i+1).append("parinte "+nume. if(nume.isFile()){ 50 . }catch(IOException ioe){} } public String citeste()throws IOException{ System.*. pentru a crea un filtru trebuie să scriem o clasă care implementează interfaţa FilenameFilter.io.txt: import java.getPath()+"\r\n").out. public class Filtru implements FilenameFilter{ public boolean accept(File dir. return br. în fişierul analiza. buffer. if(nume.

while((s=in.print(sir). iar pentru a trata sfarsitul fluxului de intrare folosim constanta public static finale int TT_EOF //token-ul citit conţine sfârşitul fluxului de intrare Deosebirea faţă de clasa StringTokenizer este ca aceasta clasă diferenţiaza token-ii obtinuti din fragmentare. } public void scrie(String sir) throws IOException { pw. adică a fost apelată metoda void eolIsSignificant(boolean val) cu val=true. Astfel.close().append(s+"\r\n"). respectiv cuvântul citit se folosesc următoarele variabile instanţă: public double nval //conţine valoarea numărului întors ca token public String sval //conţine caracterele cuvântului î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. public int lineno()//întoarce numărul liniei curente. clasa ofera urmatoarele constante: public static finale int TT_NUMBER //token-ul citit este un număr public static finale int TT_WORD //token-ul citit este un cuvânt Pentru a obtine numărul.append(dir[i]+"\r\n"). }catch(IOException ioe){} } else if(nume.length.i<dir. return buffer. } } Programul 1. această clasă imparte un flux in token-i. String[] dir=nume.close(). for(int i=0. diferenţiază între tipuri de token-i: şiruri.buffer. sfârşitul unei linii. i++) buffer. 51 .append("Continutul fisierului\r\n"). try{ RandomAccessFile in=new RandomAccessFile(nume.list().toString(). dar spre deosebire de prima clasă. Fisier: Lucrul cu clasa File Clasa StreamTokenizer Ca şi StringTokenizer. sfârşitul fişierului.’ si ‘–‘. Acesta este memorat dupa apelul metodei si în variabila instanţă public int ttype. in. Clasa oferă si alte metode utile în analizarea unui flux de intrare specializat: public void parseNumbers()//sunt analizate numerele si caracterele ‘.readLine())!=null) buffer. Pentru a sti daca s-a ajuns la sfarsitul liniei curente se foloseste constanta: public static finale int TT_EOL //token-ul citit conţine sfarşitul liniei curente (“\r” sau “\n”) dacă acesta este tratat ca un token.append("Continutul directorului\r\n"). pw.append("acest nume nu exista"). String s="". etc. "r"). numere. } public static void main(String[] a){ new Fisier(). } } else buffer. Constructorul clasei: public StreamTokenizer(Reader r)//creaza un tokenizer care imparte fluxul de intrare r într-un şir de token-i.isDirectory()){ buffer.

public void whitespaceChars(int min. public class Tokenizer{ private StreamTokenizer st. public void wordChars(int min.sval+" ").out.io. fara sa mai verifice tipul sau si-l intoarce ca un token de tip TT_WORD. se iau caracterele pana la acesta. import java. In acest caz.out.*. } System. int max) // toate caracterele ce au codul Unicod in intervalul [min. int max) //toate caracterele ce au codul Unicod in intervalul [min.getMessage()).} catch(IOException io){System. token-ii fluxului de intrare aflati pana la sfarsitul liniei vor fi ignoraţi. max] sunt tratate ca oarecare. }catch(IOException io){System. System.out. n. respectiv numere.out. try{ st=new StreamTokenizer(new BufferedReader(new FileReader("intrare.} } public void imparte(){ if(st==null) System. precum şi numarul de cuvinte.println(io.TT_NUMBER: System. try{ while(st. }catch(FileNotFoundException nf){System.out.out. case StreamTokenizer.print("cuvant= "+st. private int w. n++.println(io. Daca ch apare o singură dată in fluxul de intrare. public Tokenizer(){ String linie. se iau caracterele de la ch pana la sfarsitul fisierului. public void commentChar(int ch) //caracterul ch indica inceputul unui comentariu. public void ordinaryChars(int min.exit(0).println("Total numere= "+n).getMessage()). max] sunt tratate ca spatii. Dacă a doua apariţie a caracterului ch nu este găsită pana la sfarşitul liniei.txt"))). public void pushBack()//token-ul curent va fi obtinut si la urmatorul apel al metodei nextToken() Exemplu.imparte(). break.txt” si afiseaza tipul fiecarui token si valoarea sa.TT_WORD: System.public void ordinaryChar(int ch) //trateaza caracterul dat la apelul metodei ca unul oarecare. max] sunt tratate ca parte din cuvinte.out. } System. int max) // toate caracterele ce au codul Unicod in intervalul [min.println().println("Total cuvinte= "+w). break.TT_EOF){ switch(st. public void quoteChar(int ch) //caracterele gasite intre două apariţii a lui ch sunt tratate ca un literal String si intoarse ca un token de tip TT_WORD.nval+" ").ttype){ case StreamTokenizer. Sa scriem un program care citeste continutul fisierului “intrare. t.println(nf.print("numar= "+st. w++. } } 52 .getMessage()). din fisierul respectiv.nextToken()!=StreamTokenizer.} } public static void main(String[] args){ Tokenizer t=new Tokenizer().out.

ce vor ajuta la tratarea exceptiei.NullPointerException at Exceptie. Metoda din vârful stivei este cea care a aruncat excepţia respectivă. public void printStackTrace(java. Când apare o excepţie este important să captăm cauza ce a dus la apariţia ei. } După cum observăm. public void printStackTrace().excepţii controlate: erori de intrare/ieşire precum continuarea operaţiei de citire după ce s-a ajuns la sfârşitul fişierului. dacă apare o astfel de excepţie se va apela metoda printStackTrace() a clasei Throwable. } static void metoda2(int[] b){ System.PrintStream ps).stiva apelurilor metodelor. cast care depăşeşte limita unui array.excepţii necontrolate cauzate de erori de programare: cast greşit.io. executarea următorului program public class Exceptie{ static void metoda1(int[] a){ metoda2(a).io. De exemplu.java:3) at Exceptie. public void printStackTrace(java. clasa Throwable implementează mai multe metode printre care şi metoda getMessage() care returnează un şir care descrie situaţia care a cauzat excepţia.lang: public class Throwable{ public Throwable(). . } public static void main(String[] args){ metoda1(null). referinţă la un obiect null.lang.java:6) at Exceptie.9. Toate excepţiile ce pot fi generate sunt împărţite în două clase: Exception şi Error. toate excepţiile în Java sunt reprezentate de obiecte ale subclaselor clasei Throwable din pachetul java. încercarea de a deschide un URL greşit. . public Throwable fillInStackTrace(). împreună cu alte informaţii. cum ar fi valoarea variabilelor folosite.condiţie de eroare provocată de erori interne sau lipsa resurselor mediului de executie Java. clasa RunTimeException conţine tipuri de excepţii lansate automat de JVM. De aceea.main(Exceptie. ambele derivate din clasa Throwable. Toate 53 .out. } } determină afişarea mesajului: java.println(b[0]). Dacă nu sunt tratate de programator. public Throwable(String mesaj).tipul de exceptie aruncat. împreuna cu numărul liniei pe care se găseşte declaraţia metodei. GESTIUNEA EXCEPŢIILOR O excepţie este o condiţie exceptională care întrerupe execuţia unui program şi care poate fi: .situaţie particulară apărută în timpul execuţiei programului care poate fi de unul din următoarele tipuri: .java:9) Mesajul afişat conţine următoarele informaţii: . public String getMessage(). RuntimeException şi subclasele lor indică condiţii care în general nu sunt corecte şi care de obicei generează terminarea unui program. Error.metoda2(Exceptie. . De exemplu. Subclasele lui Exception. cu excepţia lui RuntimeException şi a subclaselor sale. public String toString().metoda1(Exceptie. fiecare cu clasa şi unitatea de compilare de care aparţine.PrintWriter pw). indică situaţii particulare care nu sunt erori.

Depăşirea stivei de execuţie. Memorie insuficientă creării unui obiect nou. Se accesează un fişier care nu există în locaţia specificată de program. Se memorează într-un array o valoare de tip diferit de tipul de date al array-ului. Clasa respectivă trebuie să fie importată sau scrisă de către programator.pachetele incluse în JDK generează diferite tipuri de excepţii. O parte din acestea sunt prezentate în figurile de mai jos şi unele din acestea sunt explicate în următorul tabel: Exceptie ArithmeticException ArrayIndexOutOfBoundsException ArrayStoreException ClassNotFoundException FileNotFoundException IOException NullPointerException NumberFormatException OutOfMemoryException SecurityException StackOverflowException StringIndexOutOfBoundsException Cauzată de Erori matematice cum ar fi imparţirea la zero. Se încearcă folosirea unei clase pe care compilatorul nu o cunoaşte. 54 . Un applet înacearcă să realizeze o acţiune care nu este permisă de browser. Indicele unui array este în afara array-ului. Erori generale de I/O. Referirea unui obiect null. cum ar fi incapacitatea de citi dintr-un fişier. O conversie eşuată între şiruri şi numere. Programul incearcă să acceseze un caracter de pe o poziţie care nu există în şir.

Excepţii ş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 .

Argumentul metodei poate să nu fie utilizat în codul gestorului.Cum utilizăm excepţiile? Există mai multe alternative pentru programator: . iar alegerea gestorului este în întregime bazată pe tipul excepţiei. Această situaţie va fi detectată de compilatorul Java şi va reporta o eroare.se încearcă repararea unei greşeli şi se continuă fără să se reapeleze metoda. . . ea poate fi “prinsă” (catch) de gestorul excepţiei respective. deoarece în cazul apariţiei unei excepţii. se va executa codul din blocul finally: void metoda2(){ try{ //cod care poate produce o exceptie }catch(Exception e){ 56 . deoarece primul este mai general şi va trata şi excepţiile de intrare/ieşire (deoarece IOException este o subclasă a lui Exception).simplifică dacă schema de elaborare a excepţiilor aleasă complică lucrurile. Dacă apare o excepţie ca rezultat al executării uneia din instrucţiunile blocului. următoarea metodă gestionează interceptarea unei excepţii şi a unei erori şi indiferent dacă acestea apar sau nu. Tratarea excepţiilor prezintă următoarele avantaje: .catch) şi ce trebuie să facă pentru a împiedica apariţia unei excepţii.corectarea problemei şi apelarea metodei care a cauzat excepţia.se face tot ce se poate în contextul curent şi se relansează o excepţie diferită în contextul superior. acest lucru înseamnă că al doilea gestor niciodată nu va trata nici o excepţie. Pentru acelaşi bloc try putem avea mai mulţi gestori. De exemplu. .. Mecanismul de gestiune a excepţiilor furnizează reguli care impun cine este capabil să genereze excepţii (throws) şi când (throw). Gestorii excepţiilor pentru un bloc try sunt introduşi cu cuvântul cheie catch şi urmează blocul try.elaborarea unui rezultat alternativ raportat la cel produs în mod normal de metodă. chiar dacă apare o excepţie şi furnizează un spaţiu util de a scrie cod care să fie executat indiferent ce se întâmplă. Interceptarea şi tratarea excepţiilor Interceptarea şi tratarea excepţiilor se realizează de către gestorii de excepţii (exception handler). . In acest caz este importantă ordinea gestorilor. Când în interiorul unei metode va fi lansată o excepţie sau apelul unei metode lansează o excepţie. In exemplul următor. Fiecare gestor de excepţii este ca o metodă care primeşte un unic argument care are tipul unei excepţii şi va fi executată în cazul în care apare o excepţie de tipil respectiv. în mod normal.se termină programul. 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. Se va executa primul gestor care verifică excepţia.se face tot ce se poate în contextul curent şi se relansează aceeaşi excepţie în contextul superior. Aceasta e desigur o investiţie bună pe termen scurt (pentru debugging) şi pe termen lung (pentru robusteţea programului). Dacă nu se doreşte ca metoda respectivă să fie abandonată. Blocul crează un mediu (spaţiu de nume) în interiorul metodei. se verifică tipul excepţiei cu fiecare gestor în ordinea în care apar dupa blocul try. .face mai fiabile programul şi librăriile utilizate. cine va încerca excepţiile (try. Un bloc finally conţine instrucţiuni ce vor fi executate întotdeauna. controlul abandonează metoda. instrucţiunile ce pot genera cel puţin o excepţie se includ într-un bloc try care “încearcă” să le execute. . iar restul se ignoră.

//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 excepţie de tip: - Exception pentru orice excepţie din bibliotecile Java; - specializat pentru un pachet Java (de exemplu IOException); - definit de programator. Declaraţii throws Dacă o metodă nu tratează toate excepţiile ce pot apare atunci când este executat corpul său, atunci ea trebuie să declare în header-ul său toate tipurile de excepţii care pot să apară şi nu le tratează. Pentru aceasta se inserează o declaraţie throws după parametrii metodei şi înainte de corpul său:
modificatori numeTip numeMetoda(listaParametri) throws listaNumeTip{ //lista de instructiuni }

unde listaNumeTip::=numeTip [, numeTip]* Excepţiile 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 următoarele situaţii: - metoda este apelată dintr-un bloc try care are gestori capabili să prindă toate tipurile de excepţii 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 excepţii ce pot fi aruncate de metoda apelată. Pentru celelalte tipuri de excepţii, 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 excepţii ce pot fi aruncate trebuie să apară în declaraţia throw a metodei apelante. Notă: Excepţiile de tip Error, RuntimeException şi a subclaselor sale nu trebuie să fie declarate cu throws. Următoarea metodă returnează un caracter citit de la tastatură:
public char citesteCaracter() throws IOException{ return (char)System.in.read(); }

Lansarea excepţiilor În timpul proiectării programului sau în timpul depanării, dacă se consideră necesar ca o metodă să lanseze o excepţie, se execută următorii paşi: - căutarea clasei de excepţii corespunzătoare; - dacă metoda nu tratează excepţia apărută, se declară că apelul metodei va lansa o excepţie (cu ajutorul lui throws şi clasa de exceptie găsită la pasul anterior); - crearea unui obiect al acelei clase; - lansarea obiectului creat imediat după punctul în care se verifică excepţia, folosind instrucţiunea throw; Exemplu. Metoda următoare citeşte caracter cu caracter o linie de la tastatură pe care o returnează metodei apelante care trebuie să trateze excepţia 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 excepţiei în sus continuă până când excepţia va fi interceptată de o metodă activă care se angajează să o rezolve sau până când ajunge în vârful stivei şi aplicaţia se termină. Următorul exemplu arată cum se poate citi conţinutul unui fişier şi să detectăm sfârşitul fişierului aruncându-se o excepţie 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(); } }

Observaţie: Cum EOFException este o subclasă a lui IOException, metoda readData() tratează excepţia apărută, deci ea nu va fi aruncată metodei apelante. Important: lansând o excepţie, metoda nu o returnează apelului. Se pot crea clase de excepţii noi. Trebuie să avem o clasă care extinde clasa Exception sau un alt tip apropiat ca semantică cu excepţia noastră, în care să redefinim constructorii. De exemplu, ne definim o clasă excepţie 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 excepţie poate fi rearuncată şi dintr-un bloc catch. Atunci putem avea mai multe metode din lanţul de metode active care să trateze excepţia, poate fiecare din acestea indeplinindu-si partea sa din restaurarea stării programului astfel încât acesta din urmă să-şi poată continua execuţia după ce excepţia a fost tratată.

59

în al doilea caz. mult mai complexe. programatorul poate fi interesat de o colecţie în care fiecare componentă se găseşte într-o poziţie bine stabilită în raport cu alte componente sau colecţia nu impune nici o ordine poziţională. relaţiile dintre componentele unei colecţii nu mai sunt de ordine totală. acces rapid dacă indexul este cunoscut Căutare mai rapidă decât într-un array neordonat Inserare şi eliminare rapide Acces “last-in. sintetizate de o dată cheie. dar atunci când este navigată se pot întâlni duplicate care pot crea confuzie.verificarea dacă grupul este vid sau conţine cel puţin un obiect. care formează întodeauna o colecţie. Pentru fiecare tip de colecţie. Diferenţele dintre colecţii se datorează fie din exigenţele ce privesc navigarea într-o colecţie. cu avantajele şi dezavantajele lor de utilizare.10. cum ar fi personalul unei întreprinderi. . . Arborele Dezavantaje Căutare lentă.conţinutul obiectelor conţinute. În alte situaţii. nu este unica posibilitate de a găsi un element fie prin navigarea componentelor sau prin identificarea lui prin intermediul un număr de ordine. TIPOLOGII DE COLECŢII Pentru a găsi soluţii standard la problema colecţiilor este mai întâi necesar să identificăm tipurile de colecţii după care modul în care se doreşte elaborarea colecţiei.eliminarea tuturor obiectelor din grup.adăugarea la grup sau eliminarea din grup a unui grup de obiecte. Tabelul 10-1 reaminteşte principalele structuri de date. Deseori trebuie să executăm operaţii care privesc întregul grup. trebuie să proiectăm algoritmi şi structuri de date corespunzătoare. ca în cazul listelor.verificarea că un anumit obiect există în grup. capacitate limitată Căutare lentă Acces lent la componentele care nu sunt în vârf Acces lent la componentele care nu sunt în vârf Algoritm de eliminare complex pentru ca arborele să rămână balansat Este complex. capacitate limitată Căutare lentă. conturile bancare ale clienţilor unei bănci sau comenzile făcute în ultima perioadă. pot fi oferite servicii care satisfac exigenţele programatorilor. Este cazul arborilor şi a grafurilor care necesită modalităţi sofisticate de abordare. inserare şi eliminare rapidă (dacă arborele rămâne balansat) Căutare. . . În schimb. Astfel de grupuri de obiecte se numesc colecţii şi pentru a le putea elabora. COLECTII STRUCTURI DE DATE DINAMICE Presupunem că avem nevoie să utilizăm grupuri de obiecte care au unele proprietăţi comune.adăugarea unui nou obiect la grup. fie din natura sa: colecţia de obiecte sau relaţii de tipuri funcţionale între două colecţii. eliminare lentă. avem tipul mulţime (Set). eliminare lentă. În primul caz avem tipul listă (List) de colecţie. Numărul componentelor din grup nu este cunoscut de obicei cunoscut de la început şi poate varia după necesităţile aplicaţiei. Este cazul relaţiilor care sunt colecţii de legături între o cheie şi componenta asociată (tipul Map). ci de oridne parţială. inserare şi eliminare rapidă. De exemplu. first-out” Căutare. În anumite aplicaţii poate fi util să găsim o componentă prin intermediul proprietăţilor ei. .eliminarea unui obiect existent din grup. 60 . Structura de date Array Array ordonat Listă înlănţuită Stivă Coadă Arbore binar Arbore binar de Avantaje Inserare rapidă. first-out” Acces “first-in. în schimb. Utilizarea unui astfel de grup este necesară din următoarele motive: . cum ar fi: .

Implementarea in Java a unui nod al listei este: 61 . Fiecare nod contine doua campuri: – primul contine un element al listei. returnand true daca x se gaseste in lista. 5. Se va sterge prima apariţie a elementului x în listă. an este ultimul element in lista. Principalele structuri de date 10. L=(x. Daca numarul este zero. utilizează ineficient memoria. – al doilea contine o referinta la urmatorul nod al listei. atunci primul element se numeste capul listei.1. 4. De obicei. Arborele este întotdeauna balansat. De asemenea. ….1 Structura de date listă O listă este o secvenţa finită de zero sau mai multe elemente. Acces rapid la componente mai mari. ai+1. (ai. Stergerea unui element din listă. Orice algoritm este complex şi lent Tabelul 10-1. Ca un caz special. 29) O linie de text este o lista de caractere. Notatie () sau ε. Acces foarte rapid dacă se cunoaşte cheia. 7. Sufixul unei liste este o sublista care se termină la sfarşitul listei. Aceasta operatie este logică.11. elementAt(i. 7. Exp. a1. 13. inserare şi eliminare rapidă. 23. 3. Notatie. …. o lista este este scrisă specificandu-se elementele sale ai: (a1. iar restul listei formează coada listei. an). prim(L) intoarce primul element al listei şi ultim(L) intoarce ultimul element al listei . an) este o listă. Ambele genereaza o eroare daca lista este vida. 8. Daca L=(a1. putem spune că aI apare la poziţia i in lista. Lungimea unei liste este numărul de apariţii a elementelor listei. Operaţii asupra listelor 1. Stergerea tuturor elementelor din lista. Implementarea listelor Modul cel mai uşor de a implementa o lista este să folosim o lista de noduri legate între ele. Daca o lista este nevidă. an) Exemple: Lista numerelor prime 10 numere prime naturale: (2. Inserare şi eliminare rapide Modelează situaţii frecvente în lumea reală Dezavantaje Este complex. iar lista initiala va deveni coada. Eliminare lentă.5. Inserarea unui element x într-o listă L. Asadar. a2 al doilea. Acces lent la alte componente. Daca x nu apare in lista. 6. 17.3. 1≤i≤j≤n. L) returneaza elementul de pe pozitia i a listei L. Prefixul unei liste este orice sublista care incepe la inceputul unei liste. Poate fi utilizat pentru file systems Căutare. aj) este o sublista a lui L. Putem cauta un element intr-o lista L. …. …. atunci lista este vidă. a2. atunci pentru orice i şi j a. 19. numarul de poziţii ale unei liste formeaza lungimea listei.i. Exp.Structura de date căutare Arbore rosu-negru Tabel hash Heap Graf Avantaje este întotdeauna balansat. lungime(L) returneaza lungimea listei L. L2) două liste L1 şi L2. Avem eroare daca L este de lungime mai mica decat i. Inserare rapidă. acces lent dacă cheia nu este cunoscută. 2. esteVida(L) returnează true daca L nu contine nici un element. Dacă L=(a1. spunem că lista este de tip T. a2. a2. an) şi n≥1 atunci a1 este primul element. atunci operatia de stergere nu are nici un efect. …. In principiu x ar putea să apară oriunde in listă şi nu contează dacă x apare de mai multe ori. 9. samd. Un document este o lista de linii de text. Dacă toate elementele sunt de acelaşi tip T. fiecare element din listă are asociată o poziţie. a2. putem insera pe x la inceputul listei şi atunci x va fi capul noii liste. concateneaza(L1.

nr).next. Nod n){ element=o.nr++. } //adauga un element la sfarsitul listei public void adaugaElement(Object o){ Nod n=new Nod(o). Variabila next din nodul i contine o referintă la nodul (i+1). pentru fiecare element al listei avem cate un nod. } //inserarea unui element la o anumita pozitie public void insereazaElement(Object o. } else { Nod curent=nodLa(index-1).next=n.public class Nod{ private Object element. pt i=1. next=n. private int nr.} if (verificaPozitie(index)){ Nod n=new Nod(o). public Nod(Object o){ element=o. if (esteVida()){cap=n. n. elementul ai apare în campul element al nodului i. 62 . public boolean esteVida(){ return lungime()<=0. return. an) este reprezentata ca o listă linked-itata astfel: a1 a2 … an Implementarea în Java a operaţiilor asupra listelor linked-itate este realizată în următorul program: public class Lista{ private Nod cap. private Lista coada. int index){ if (esteVida() && index==0){adaugaElement(o). curent. …. } } Atunci. indicând sfarşitul listei.} else insereazaElement(o. } } //verificarea pozitiei unui element private boolean verificaPozitie(int index){ if (index>lungime() || index<0) return false. cap=n. } public int lungime(){ return nr. } public Nod(Object o. n-1. if(index==0){ n. } nr++.next=curent.next=cap. private Nod next. a2. Variabila next al ultimul nod este null. De exemplu: lista L=(a1.

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 operaţiile sunt realizate la un capăt al listei, care se numeşte vârful stivei. Stiva este o structură de date LIFO adică “last-in first-out (ultimul intrat, primul ieşit)”. Modelul abstract al unei stivei este acelaşi cu cel al unei liste – adică o secvenţă de elemente a1, a2,…, an de un anumit tip. Ceea ce deosebeşte o stivă de o listă este setul de operaţii permise aupra unei stive.
Operaţii asupra unei stive

Inserarea unui element x într-o stivă S, push(x, S), determină punerea elementului x în vârful stivei S. Dacă stiva are vârful capătul stâng al stivei, operaţia push(x) aplicată listei (a1, a2,…, an) generează lista (x, a1, a2,…, an). Stergerea elementului din vârful stivei este realizată de metoda pop(S). Aceasta va sterge elementul din vârful stivei şi va fi returnat de către 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

} } In continuare. } varf=lista[0]. i++) s+=lista[i]+". poz). } public void push(Object x){ if (esteVida()) lista[0]=x. 1. else { System. public class Stiva{ private Lista l. } public Object pop() throws ListaException{ if (esteVida()) throw new ListaException("Stiva este vida"). lista. } //returneaza lungimea stivei public int lungime(){ return poz. 66 . i++) lista[i]=null. i<poz-1.adaugaElement(x). lista.private static int nr=10.arraycopy(lista. varf=null. s+=lista[poz-1]+")". i<poz. Object o=varf. 1.arraycopy(lista. } public String toString(){ String s="(". lista[0]=x. } public void stergeToateElementele(){ for (int i=0. return o. public StivaArray(){ lista=new Object[nr]. poz-1). } public void push(Object x){ if (esteVida()) l. 0. poz=0. private int nr. if(poz!=0){ for (int i=0. public Stiva(){ l=new Lista(). } //verifica daca stiva este vida public boolean esteVida(){ return lungime()<=0. poz++. ". System. private int poz. } else s+=")". return s. poz--. private Object varf. vom implementa dinamic o stivă cu ajutorul listelor simplu înlănţuite. 0.

}catch(ListaException le){varf=null.elementulDeLa(1).else l. esteVida(C) returnează true dacă C nu contine nici un element Implementarea unei cozi Vom implementa operaţiilor ce pot fi executate asupra unei cozi cu ajutorul unei liste simplu înlănţuită. an).toString().} l. şi şterse pe la celălalt capăt al listei numit început. lungime(C) returneaza lungimea coadă C. 0). first-out. Operaţii asupra unei cozi - introduce(C. } //verifica daca stiva este vida public boolean esteVida(){ return lungime()<=0.….elementulDeLa(0)). }catch(ListaException e){} nr++. o coadă este o structură de elemente în care putem insera şi sterge elemente după politica FIFO: first-in. } public String toString(){ return l. Dacă coada începe din capătul stâng al listei. 67 . stergerea tuturor elementelor din coadă.stergeToateElementele(). } } 10. numit sfârşit.1. an. x) adaugă elementul x la sfârşitul cozii. try{ varf=l. Object o=varf. } public Object pop() throws ListaException{ if (esteVida()) throw new ListaException("Stiva este vida"). x). } //returneaza lungimea stivei public int lungime(){ return nr. nr--. nr=0. atunci operaţia va genera o eroare.…. extrage(C) extrage elementul de la începutul cozii.prim(). varf=null. operaţia extrage() aplicată listei (a1.…. Mai precis.stergeElement(l. a2. an) generează lista (a2.3 Structura de date coadă O coadă este un model de date bazat pe modelul listă în care elementele sunt inserate pe la un capăt al listei. } public void stergeToateElementele(){ l. public class Coada{ private Lista l.insereazaElement(x. return o. a2. Dacă coada este vidă. stergeToateElementele(C). try{ varf=l. iar operaţia introduce(x) generează lista (a1.

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

out. Aşadar.println(e.st. 69 . putem defini înălţimea unui arbore ca fiind maximul dintre nivelurile nodurilor frunză. se numeşte nod frunză (sau terminal). orice nod.out.stergeToateElementele(). Aceştia sunt numiţi subarborii lui A. în sensul că orice două muchii succesive din cale au un nod comun. System. nodul n3 este părinte pentru nodurile n5 şi n6 şi fiu pentru rădăcină. putem caracteriza următorul arbore astfel: n1 n2 n3 n4 - n5 n6 n7 - rădăcina arborelui este n1.(n3.getMessage()).4 Structura de date arbore Un arbore este format dintr-o mulţime de noduri legate prin muchii ce îndeplinesc următoarele condiţii: . nodurile n2. datorită relaţiei de “subordonare” faţă de rădăcină. cu excepţia nodului rădăcină. c.out.out. fiecare cu rădăcina n2. }catch(ListaException e){System.} } } 10. al cărei nivel este. iar p este un fiu al lui c. n5. prin convenţie. c. are trei subarbori.out.conţine un nod special. un arbore este conectat. orice muchie leagă două noduri distincte.introduce(s[2]). Aşadar.out.stergeToateElementele().out. n6) este calea de la rădăcină la nodul n6.extrage(). un arbore A se poate defini ca fiind format dintr-un nod rădăcină de care este legată o mulţime finită de arbori. In cazul în care un nod nu are noduri fii. try{ Student o=(Student)c.println(c). nodul c este părintele lui p. în sensul că accesul de la rădăcina unui (sub)arbore nevid la oricare al nod presupune parcurgerea unei căi formate din a muchii (a≥0) pe care se găsesc n noduri (n=a+1). System. are un singur nod părinte şi poate avea mai mulţi fii.introduce(s[1]). System. In acest caz. System. c. De aceea. System. orice nod c diferit de rădăcină este legat de un alt nod p al arborelui printr-o muchie. (n1.1. O muchie este indicată prin perechea de noduri pe care le leagă.println(c).} Coada c=new Coada().println(st). numit nod rădăcină. 1. c. De exemplu. Valoarea n reprezintă nivelul pe care se găseşte nodul faţă de rădăcină. n7 şi n4 sunt noduri frunză.println("scoate= "+o). n3). }catch(ListaException e){System. o cale într-un arbore este o succesiune de muchii adiacente două cate două. n3 şi n4.getMessage()).introduce(s[0]). In plus.println(c).println(e.

} public void setNodDrept(Nod s){ drept=s.arborele este de nivel 4. căutarea unui element în arbore. adică cu arbori ai căror noduri au cel mult doi fii (direcţi). 2. adică vizitarea nodului curent si apoi a subarborelui stâng. drept=r. apoi a acestuia din urmă şi pe urmă subarborele drept. Similar. In continuare. informaţia din nodurile unui arbore va fi afişată în funcţie de ordinea în care arborele binar a fost parcurs. Implementarea in Java a unui nod al unui arbore binar este dată în continuare: public class Nod{ private int info. public Nod(int inf){ info=inf. vom lucra numai cu arbori binari. cei doi potenţiali subarbori ai unui arbore nevid se numesc subarbore stâng şi subarbore drept.postordine.adăncimea arborelui este egală cu 4. inserarea unui element în arbore. 70 . După cum ştim. . . 4. afişarea arborelui. } public Nod getNodDrept(){ return drept. stang=l. Nod r){ info=inf. private Nod stang.info=info. drept. Nod l.inordine presupune parcurgerea subarborelui stâng al nodului curent. adică nodul curent este vizitat după ce au fost parcurşi cei doi subarbori.. } public int getInformatie(){ return info. cei doi potenţiali fii ai unui nod al unui arbore binar se numesc fiu stâng. ştergerea întregului arbore.preordine. respectiv fiu drept. stergerea unui element din arbore cu returnarea unei valori logice care ia valoarea true dacă elementul există în arbore. modificarea informaţiei memorată în rădăcina arborelui. } public Nod getNodStang(){ return stang. } public Nod(int inf. . respectiv drept al acestuia. } public void setInformatie(int info){ this. } } Operaţii asupra aborilor binari Asupra unui arbore binar putem executa următoarele operaţii: 1. începând cu rădăcina arborelui: . 5. 6. 3. In acest caz. Operaţia va începe cu rădăcina arborelui şi va returna valoarea false dacă elementul nu a fost găsit. } public void setNodStang(Nod s){ stang=s.

false). nou=false. else { n. } } Căutarea unui element într-un arbore binar de căutare Următorul algoritm recursiv descrie paşii necesari căutării unui element x în arborele A. Ordonarea este cea obişnuită dacă informaţiile sunt numerice sau este de tip lexicografică dacă avem de-a face cu caractere sau şiruri de caractere.getNodDrept(). inaltime=1. } } if (nou) inaltime++.getNodDrept()==null) nou=true. Nod n. else if(element<n. atunci se inserează x în subarborele stâng al rădăcinii dacă x este mai mic decât informaţia rădăcinii sau se inserează în subarborele drept al rădăcinii dacă x este mai mare decât informaţia conţinută în rădăcină. if (n1!=null) insereaza(element. n. null. if (p==null || p.setNodDrept(new Nod(element. if (n1!=null) insereaza(element. Pentru aceasta. null)). n1. } else { if(n. false). Dacă A nu este vid şi x nu se găseşte ca înformaţie a unui nod oarecare al arborelui. if (p==null || p.getInformatie()) { Nod n1=n. Dacă A este vid. Dacă A este vid.getNodStang(). Nod p. atunci înălţimea arborelui este incrementată cu o unitate. Pas recursiv. cautare şi ştergere a unui element in/dintr-un arbore binar ce îndeplineşte următoarea proprietate: informaţiile nodurilor sunt ordonate astfel încăt informaţia unui nod oarecare este “mai mare” decât informaţia oricărui nod al subarborelui stâng al său şi este “mai mică” decât informaţia oricărui nod al subarborelui drept al său. dacă un nod conţine o informaţie egală cu x. Metoda următoare implementează în Java acest algoritm: private void insereaza(int element.getNodStang()==null) nou=true.setNodStang(new Nod(element. else { n. atunci x este deja în arbore şi operaţia se termină. Altfel. Inserarea unui element într-un arbore binar de căutare Următorul algoritm recursiv descrie paşii necesari pentru ca un element x să fie inserat în arbore A: Baza. boolean nou){ if (esteVid()){ rad=new Nod(element). null)). adică nodul curent (care iniţial va fi rădăcina) analizat este null atunci x nu se găseşte în arbore. n. n1. null. Dacă unul din subarbori nu există şi ne aflăm pe un nivel nou al arborelui. avem nevoie să ştim nodul părinte al nodului curent.getInformatie()==element) return. atunci se crează un nod ce conţine elementul x şi acesta va fi rădăcina arborelui. 71 . începând bineînţeles cu rădăcina acestuia: Baza. } } else{ Nod n1=n.In continuare vom exemplifica implementarea operaţiilor de inserare.

getNodStang(). dar mai mare decât x este: int stergeMinim(Nod n.setNodStang(null). Stergerea unui element într-un arbore binar de căutare Următorul algoritm descrie paşii necesari ştergerii unui element x în arborele A: 1. } else return stergeMinim(n.getNodStang()."d").getNodStang()==null && n. if (p. informaţia mai mare decât x. îl căutăm în subarborele drept. n. else //nodul este un nod frunza if(n.setNodStang(n). Nod p. n.getNodDrept()).Pas recursiv. Dacă nu suntem în condiţiile bazei. Nod p. n.getNodDrept()==null) inaltime--.getInformatie()==element) return true. else if(n. else if(element<n. else if(element>n. } iar metoda următoare implementează întregul algoritm descris mai sus: private boolean sterge(int element. Apoi nodul y se şterge din arbore. atunci se caută nodul y ce conţine cea mai mică informaţie din subarborele drept al nodului curent. n.getNodStang()).n. 2. după ce informaţia conţinută de el este memorată în nodul curent. if(n. ne aflăm în unul din următoarele cazuri: dacă nodul curent este nod frunză. atunci algoritmul se termină cu valoarea false. Dacă A nu contine nici un nod ce conţine x.getNodDrept(). else //aici ambele noduri fii nu sunt null 72 . Nod n.getInformatie(). String poz){ if(n!=null){ if(element<n. n=n. Nod n){ if (n==null) return false. Metoda următoare implementează în Java acest algoritm: private boolean cauta(int element. } cauta(element. atunci primul este înlocuit cu al doilea nod.setNodDrept(n).n. atunci căutăm x numai în subarborele stâng al nodului curent.getNodStang(). String poz){ int min. else p.getNodDrept()==null) { if (poz=="s") p.getInformatie()) return sterge(element. atunci acesta se şterge şi referinţa nodului părinte la nodul respectiv este setată la null. } else if(n. - Metoda ce determină nodul cu informaţia cea mai mică. if (poz=="s") p.getInformatie()) return n. Altfel.getNodDrept().getNodDrept()==null) n=n.getNodDrept(). fie y informaţia nodului curent. return min. dacă nodul curent are un singur nod fiu. trebuie să ştim ce tip de fiu era pentru nodul părinte: stâng sau drept. else return cauta(element.getNodStang()==null && p. dacă nodul curent este un nod interior. Dacă x<y. "s"). "s"). else if (n. Altfel.getNodStang()==null){ min=n. De aceea.setNodDrept(null).getNodStang()==null) n=n.getInformatie()) return sterge(element. else p.

else afiseaza(rad. else if (forma.getInformatie()). } } Celelalte operaţii nu necesită explicaţii.println(n. } private void preordine(Nod n){ if (n==null) return. inaltime=1. preordine(n. } public boolean esteVid(){ return rad==null. private int inaltime. "d")).getInformatie()). inordine(n. inordine sau postordine.getInformatie()). iar metodele asociate furnizează interfaţa clasei Arbore: public class Arbore{ private Nod rad.getNodStang()).equals("postordine")) postordine(rad). } public Nod getRadacina(){ return rad. preordine(n. Nod st.equals("inordine")) inordine(rad).getNodDrept()). public void afiseaza(String forma){ if (forma. else if (forma. 0).setInformatie(stergeMinim(n. } private void inordine(Nod n){ if (n==null) return.out. 73 .getNodDrept(). postordine(n.getNodDrept()). System.getNodStang()). } public void stergeArbore(){ rad=null.getNodStang()). } private void postordine(Nod n){ if (n==null) return. return true. inordine(n.setInformatie(info). dr).println(n.println(n. Nod dr){ rad=new Nod(inf.out.n. } public void modificaInformatie(int info){ rad.equals("preordine")) preordine(rad).getNodDrept()). } return false.out.n. System. st. public Arbore(){} public Arbore(int inf. System. postordine(n. } Afişarea informaţiilor unui arbore binar de căutare Următoarele metode recursive arată diferite modalităţi de a afişa informaţiile unui arbore binar de căutare prin parcurgerea acestuia din urmă în preordine.

else if (forma.mulţimea angajaţilor unei întreprinderi .equals("postordine")) postordine(rad). rad. 74 .. else afiseaza(rad. chiar dacă colecţia a fost definită având o semnificaţie mai generală. null).equals("preordine")) preordine(rad). 2 .mulţimea obiectelor Component dintr-un Container . fără nici o legătură între ele. Exemple de mulţimi sunt numeroase. 'class'.maparea adreselor IP la nume dintr-un domeniu de nume DNS. etc.. mapping). 10.mulţimea cuvintelor cheie din Java: {'import'. Collections Framework furnizează un API convenabil oricăror tipuri de date abstracte utilizate frecvent în informatocă: relaţii. } } COLECŢII ÎN JAVA Java furnizează o structură de clase şi interfeţe numită Collections Framework specializată în memorarea şi elaborarea colecţiilor de obiecte. în Collections Framework o mulţime este o colecţie de elemente unice. Exemple de mapări sunt: . } public boolean cauta(int element){ return cauta(element. arbori. } public boolean sterge(int element){ return sterge(element.5 Teoria de bază a colecţiilor La baza teoriei colecţiilor stă conceptul matematic de mulţime. adică o colecţie fără elemente duplicat. clasele din Collections Framework încapsulează atât structura de date cât şi algoritmii asociaţi acestor abstractizări. } public void afiseaza(String forma){ if (forma. rad. În schimb. array. false). de grup de elemente. 0).} public int getInaltime(){ return inaltime. . . else if (forma. } public void insereaza(int element){ insereaza(element. liste.} . Este o mulţime de legături în care fiecare legătură reprezintă o conexiune de la un element la un altul.conversia unui sistem de numeraţie la un alt sistem de numeraţie (sistemul arabic la cel roman).mulţimea vidă {} Un caz particular de mulţime este relaţia funcţională sau maparea (în engleză.. 'public'. null. null.} . 1. Iată unele: .1. Datorită orientării spre obiecte. 'protected'.dicţionar (maparea cuvintelor la înţelesurile lor).mulţimea literelor mari de la 'A' la 'Z' .equals("inordine")) inordine(rad). rad). mulţimi..mulţimea numerelor nenegative: {0.

Unele interfeţe sunt implementate de clase Java ce aparţin aceluiaşi pachet java. Interfeţe de colecţii şi implementările lor 75 . Pentru mapare.util şi conţine interfeţe care se găsesc în relaţii de generalizare/specializare ca cea prezentată în Figura 10-2. biblioteca Java conţine clase ce furnizează rapid obiectele Cheie1 Cheie2 Cheie3 Cheie4 Cheie5 legatura1 legatura2 legatura3 legatura4 legatura5 Valoare1 Valoare2 Valoare3 Valoare4 Valoare5 căutate indicând numai cheia asociată. Aceste Collection Map Set List SortedMap SortedSet clase reprezintă colecţii de obiecte sau relaţii între obiecte şi sunt prezentate în Tabelul 10-2.1. Interfete ale Collections Framework Interfaţa Set SortedSet List Map SortedMap HashMap TreeMap ArrayList HashSet TreeSet LinkedList Vector Stack Hashtable Properties Implementare Precedenţi istorici Tabelul 10-2.O mapare (Figura 10-1) poate servi la navigarea de la un element al unei legături la un alt element.6 Collections Framework Collections Framework este furnizat în pachetul java. Maparea între chei şi valori 10. Figura 10-2. Figura 10-1.util.

<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. Hashtable şi Properties. ListIterator. 76 .1 Interfeţe fundamentale Clase concrete utile HashSet TreeSet <interface> Map Vector ArrayList <abstract> AbstractSequentialList HashMap Stack LinkedList Figura 10-3. clasele abstracte şi clasele concrete din Collections Framework şi relaţiile dintre ele.0. În plus. Collections Framework Interfaţa Collection java.util. Operaţiile interfeţei Collection sunt prezentate în tabelul următor. Această interfaţă este utilizată ca numitor comun al altor interfeţe.Schema completă a lui Collections Framework este prezentată în Figura 10-3. Schema prezintă în diferite nuanţe de gri interfeţele. numite elementele colecţiei. sunt marcate clasele care provin din versiuni mai vechi cum ar fi Vector. pentru a permite transferul colecţiilor de la un tip de colecţie la un alt tip şi elaborarea lui cu generalitate maximă. 1. Collections Framework mai conţine şi alte interfeţe cum ar fi Iterator.Collection este o interfaţă standard ce reprezintă un grup de elemente. Biblioteca Java nu conţine o implementare directă a interfeţei Collection. Stack. Comparator şi Comparable care permit navigarea colecţiilor şi compararea elementelor dintr-o colecţie.

Dacă elementul o se găseşte in colecţie. Array-ul returnat este de acelşi tip cu array-ul transmis ca parametru. filtrul va fi implementat astfel: Collection colectie = . să filtrăm o colecţie. nu mai adaugă elementul o şi întoarce false.hasNext()) { Object element = iterator.iterator().. Elimină toate elementele care nu fac parte din colecţia transmisă ca argument.next().. Dacă operaţia are loc cu succes. În caz pozitiv. Presupunem că avem o metodă verificaEliminare(Object o) care întoarce true dacă obiectul transmis ca parametru va fi efectiv eliminat. metoda returnează false. boolean remove(Object o) boolean contains(Object o) Iterator iterator() int size() boolean isEmpty() Operaţii pe grupuri de obiecte boolean addAll(Collection c) boolean removeAll(Collection c) boolean retainAll(Collection c) void clear() Operaţii cu array Object[] toArray() Object[] toArray( Object []) Iterfaţa Iterator Iterator este o interfaţă implementată de un obiect obţinut prin invocarea metodei iterator() a unui obiect din clasa Collection.remove(). Returnează true dacă colecţia conţine elementul o Întoarce un obiect de tip Iterator care se poate utiliza pentru navigarea colecţiei. Adaugă toate elementele colecţiei c. Nu introduce alte metode diferite de cele din Collection. while (iterator. de exemplu. Iterator iterator = colectie. Întoarce numărul de elemente ale colecţiei Returnează true dacă colecţia nu are elemente. if (verificaEliminare(element)) { iterator..Declaraţie metodă Operaţii de bază boolean add(Object o) Semnificaţie Verifică dacă colecţia conţine elementul o. Interfaţa Set extinde interfaţa Collection şi împiedică crearea de elemente duplicat în colecţie. este eliminat şi meoda returnează true. metoda întoarce true. Elimină toate elementele colecţiei c. În timpul navigării putem. Goleşte colecţia Returnează un array ce conţine toate elementele colecţiei. Dacă operaţia are loc cu succes. } } Interfaţa Set Collections Framework include o interfaţă Set şi numeroase clase concrete care implementează Set. Folosind interfaţa Iterator. metoda întoarce true. Interfaţa conţine trei metode: boolean hasNext()//verifică dacă colecţia mai mai are elemente de parcurs Object next() //returnează următorul element al colecţiei void remove() //poate fi apelată numai o singură pentru fiecare obiect //obţinut cu metoda next() Iteratorul ne permite să navigăm într-o colecţie pănă la terminarea elementelor conţinute. adaugă elementul al colecţie şi returnează true. Verificarea claselor de implementare se 77 . În caz negativ. adică să eliminăm din colecţie acele elemente care nu îndeplinesc o anumită condiţie. Altfel. Returnează un array ce conţine toate elementele colecţiei.

adică să poată fi comparate între ele după o relaţie de ordine totală. şi atunci obiectul căutat nu se găseşte în colecţie şi.util. Interfaţa Set este implementată de două clase concrete Java: java. Obiectele ce vor fi adăugate la un HashSet trebuie să implementeze metoda hashCode() astfel încât obiectele vor fi egal distribuite în mod uniform cu ajutorul codurilor hash. Indexul tabelului variază între 0 şi un k-1.util. Obiectele din clasa HashSet sunt utilizate pentru memorarea colecţiilor fără duplicate.util. 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.TreeSet. int incr)//creaza o colectie HashSet de capacitate //initiala şi factor de încărcare transmise ca argumente Exemplu. având într-o listă cuvintele unice: import java. Clasa TreeSet este utilizată când vrem să lucrăm cu elementele unei colecţii ordonate. Figura 10-4 prezintă schematic ideea care stă la baza unei structuri de de date de tip hash table. Clasa HashSet Clasa implementează interfaţa Set şi este construită intern de un “hash table”.HashSet şi java. Clasa permite utilizarea unui element null în colecţie. numărul de cuvinte distincte. Vom scrie un program care preia cuvinte din linia de comandă şi vizualizează cuvintele duplicat. f i Figura 10-4. se poate adăuga. Obiectele care se adaugă la un TreeSet trebuie să fie ordonabile.bazează pe metoda equals() a obiectului care este adăugat la colecţie. public class Duplicate { 78 . Acest cod este un număr întreg calculat după un algoritm particular care implică toate câmpurile obiectului văzute ca nişte combinaţii de biţi. Dacă nu este găsit în listă.*. înseamnă că nu se găseşte în colecţie şi poate fi adăugat la lista de bucket. sau este vorba de un indicator la o listă “bucket” în care obiectul va fi căutat secvenţial. adcă este necesar. Majoritatea claselor standard redefinesc implementarea predefinită de clasa Object. el va fi folosit ca indice al array-ului central. Elementul identificat poate conţine null. În centrul structurii se găseşte un array ale cărui elemente conţin indicatori la lista înlănţuită ale cărei noduri indică elemente ale colecţiei. Odată găsit codul. Căutarea într-o astfel de structură începe cu calculul indicelui hash al obiectului care este căutat. Într-o tabelă hash nu se poate prevede care va fi ordinea de navigare între elemente. dar această ordine rămâne întotdeauna aceeaşi.

i++) if (!unice.println(sortedSet).out. set. set. public class Duplicate1 { public static void main(String args[]) { Set unice = new HashSet(). public class ExempluSet { public static void main(String args[]) { Set set = new HashSet(). } } Un alt exemplu de utilizare a clasei TreeSet este prezentat în continuare şi ilustrează utilizarea elementelor ce pot fi comparate (Comparable) şi pot fi păstrate ordonate în 79 .*. System.out.add("Andreea"). System.length. for (int i=0.println("Cuvinte unice: " + unice). Constructorii clasei TreeSet sunt: TreeSet() TreeSet (Collection c) TreeSet(Comparator comp) TreeSet(SortedSet ss) Al doilea constructor va fi utilizat în următorul program în care transmit elementele unei colecţii HashSet unui TreeSet: import java. Cuvintele care apar numai o singură dată se deduc din diferenţa celor două mulţimi.println("Cuvinte duplicat: " + dupl). i<args. import java.add(args[i])) System. set. // Diferenta dintre multimi System. i++) if (!s. set. System. Presupunem că vrem să ştim care din cuvintele din linia de comandă au apărut o singură dată şi care au apărut de mai multe ori.println("Duplicat: "+args[i]). Într-un obiect memorăm cuvintele liniei de comandă şi în al doilea obiect memorăm numai cuvintele duplicat.util. Set sortedSet = new TreeSet(set).add("Clara"). set. System. } } Clasa TreeSet Clasa implementează SortedSet care este o subinterfaţă a lui Set şi garantează că mulţimea este ordonată în ordine crescătoare.length.add(args[i]).out. unice.util.out. Set dupl = new HashSet().removeAll(dupl).out.public static void main(String args[]) { Set s = new HashSet(). 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.out. Putem utiliza două obiecte din clasa Set.add(args[i])) dupl. i<args.size()+" cuvinte distincte identificate: "+s).add("George"). } } Exemplu.add("Maria"). dar le afişăm numai o singură dată.println(set).*.println(s.add("Maria"). for (int i=0.

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

Object o) boolean addAll(int indice. elemente e1 şi e2 care verifică e1.equals(e2)) şi acceptă şi elemente null. returnează -1.nextInt(i)). Dacă nu-l găseşte. pentru a schimba locul între două elemente ale unei liste poate fi utilizată următoarea metodă: private void schimba(List a. În afara declaraţiilor de metode din interfaţa Collection. t). a. utilizatorul are un control exact al locului în care este inserat fiecare element. Object get(int indice) boolean add(int indice. Cei doi iteratori sunt folosiţi de LinkedList. rnd. } O variabilă de tip List poate conţine referinţe la obiecte ArrayList sau LinkedList care sunt implementări ale interfeţei.get(i). Utilizatorul poate accesa elementele prin intermediul iteratorilor şi a indicilor întregi care reprezintă poziţia în listă. Prin intermediul acestei interfeţe. i--) schimba(list. Returnează poziţia ultimei apariţii a obiectului o din listă. Dacă nu-l găseşte.get(j)).size(). int j) { Object t = a. a.set(j. 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. Crează o sublistă formată din elementele listei între cei doi indici transmişi ca parametri.Interfaţa List List este o interfaţă care reprezintă o colecţie ordonată (numită şi secvenţă).set(i. List are următoarele metode: Declaraţie metodă Acces după poziţie Semnificaţie Întoarce obiectul de la indicele transmis ca parametru Inserează obiectul o la poziţia indice Elimină obiectul de la poziţia indice Înlocuieşte obiectul de la poziţia indice cu obiectul o Inserează începând cu poziţia indice elementele colectiei c Returnează poziţia obiectului o din listă. int i. Random rnd) { for (int i=list. i>1. Aceşti algoritmi sunt independenţi de clasa utilizată pentru implementarea listei. int sf) Ca întotdeauna când este vorba de o interfaţă. putem implementa în mod polimorfic algoritmi valizi pentru toate obiectele claselor care implementează interfaţa. Interfaţa ListIterator 81 . returnează -1. Listele acceptă elemente duplicat (adică. De exemplu. i-1. Collection c) Căutarea unui obiect int indexOf(Object o) int lastIndexOf(Object o) Iterare ListIterator listIterator() ListIterator listIterator(int indice) Operaţie globală List subList(int in. a. Object o) Object remove(int indice) void set(int indice. În acest mod căutăm mai uşor în lista. } Vom utiliza metoda schimba() pentru a permuta elementele unei liste. Returnează un obiect de tip ListIterator al lui List Returnează un obiect de tip ListIterator al lui List.

i. metoda ListIterator. deoarece are un acces obişnuit. List valoriNoi) { for (ListIterator i = l. ) if (val==null ? i.iterator().equals(i. Interfaţa ListIterator este prezentată în continuare: interface ListIterator extends Iterator { void add(Object elem). // adaugă un element în poziţia curentă Object previous(). i.next()). în schimb previousIndex() returnează poziţia elementului întors la un apel al lui previous().add. clasa ArrayList adaugă următoarele metode: ArrayList(Collection)//construieşte un ArrayList dintr-un Collection Object clone() //clonează obiectul ArrayList void ensureCapacity(int) //garantează un număr minim pentru listă void trimToSize() //Elimină spaţiile libere din array 82 .next())) { i.add nu returnează o valoarea de tip boolean. un alt fapt: la primul apel al lui previous() după o secevnţă de apeluri next() întoarce acelaşi element al ultimului apel al lui next. // returnează indicele elementului succesiv int previousIndex().listIterator().next()==null : val. //poziţionează cursorul şi returnează elementul //precendent boolean hasPrevious().next()==null : val. cu o secvenţă de valori noi conţinute într-o listă: public static void replace(List l. Exemplu următor este cel al unei metode statice care implementează un algoritm polimorfic care înlocuieşte într-o listă oarecare toate apariţiile unui obiect val cu un obiect nou: public static void replace(List l. să o modificăm în timpul traversării şi să obţinem poziţia curentă a iteratorului. Metoda nextIndex() returnează întotdeauna elementul care va fi restituit de un apel succesiv al lui next(). // verifica dacă există un element precedent void set(Object elem). metoda următoare implementează un algoritm polimorfic care returnează toate apariţiile valorii val specificată ca parametru. Apoi.Interfaţa List furnizează un iterator mai bogat: ListIterator. } } } Clasa ArrayList ) ArrayList este o clasă concretă care implementează interfaţa List şi se sprijină pe un array fără limite de creştere.add(j. } In schimb. j. La metodele interfeţei List. În mod similar. ) { if (val==null ? i. Modelează o listă cu elemente enumerate. primul apel al lui next() după o serie de apeluri ale lui previous() returnează acelaşi element al utlimului apel al lui previous() . // suprascrie elementul curent cu elementul transmis // ca parametru int nextIndex(). În consecinţă. for (Iterator j = nuoviValori.hasNext(). Object val.equals(i. Object val.hasNext().listIterator().next())) i. Object nou) { for (ListIterator i = l.set(nou).remove(). relativ rapid.hasNext(). // returnează indicele elementului succesiv } Spre deosebire de metoda Collection. i. nextIndex() == previous()+1. care ne permite să traversăm lista în ambele direcţii. direct.

println("0: " + lista. prezentăm un program care extrage virtual dintr-un pachet de cărţi – reprezentat ca o listă . List listaNoua = pachet.addFirst("Andreea").n cărţi pentru un jucător şi le furnizează întotdeauna ca o listă: public static List furnizeazăCarte(List pachet. LinkedList aadaugă următoarele metode la cele declarate de interfaţa List : void addFirst( Object o) //adaugă o la începutul listei void addLast(Object o) //adaugă o la sfârşitul 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 Următorul program ilustrează ilustrează trasferul uşor 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.out. Cu un obiect LinkedList putem implementa cod deoarece garantează o politică FIFO în elaborarea listei.get(0)). int n) { int dimPachet = pachet.removeLast(). Are un acces aleator relativ lent (dacă accesul aleator este frecvent trebuie să fie utilizat ArrayList).addFirst("Clara"). coada.add("Clara"). public class ExempluLista { public static void main(String[] args) { List lista = new ArrayList(). listaNoua. Eliza.println(lista).*.size().println(coada).add("Eliza").addFirst("Eliza").clear(). Eliza. coada. System.subList(dimPachet-n. } } Rezultat: [Andreea.addFirst("Eliza"). Eliza. LinkedList coada = new LinkedList(). coada. } Clasa LinkedList LinkedList este o clasă concretă care furnizează un acces secvenţial optim cu operaţii economice de eliminare şi inserare în interiorul listei. dimPachet). coada. George.println("2: " + lista.add("George"). George] 83 .out. coada. System. Clara] 2: George 0: Andreea [Clara. System.get(2)). Andreea] [Clara. Eliza.addFirst("George").out. lista.println(coada). coada.add("Andreea"). System.util. Eliza. George.add("Eliza").removeLast(). coada. lista. lista. List cartiJucator = new ArrayList(listaNoua). System.out. return cartiJucator. lista. lista.În continuare.out.

4. pentru un client. HashSet. precum un LinkedList.Cum utilizăm interfaţa Collection 1. Se crează o lista de tip List ce se bazează pe un array.add(o2). Ştim că utilizarea interfeţelor este obligatorie atunci când obiectele client nu trebuie să ştie provenienţa obiectului (clasa care l-a generat) şi în general orice detalii de implementare care su fost utilizate.o altă implementare a lui Collection b Client a Înlocuirea unei implementări a lui Collection cu o alta Figura 10-5. În acest mod. Acest parametru este un obiect dintr-o clasă care implementează interfaţa Collection şi care va fi utilizat pentru a iniţializa noua colecţie. colectie memorează o referinţă la un obiect care implementează o colecţie. Implementările colecţiilor (ArrayList. colectie. TreeSet) au toate un constructor cu un parametru de tip Collection.add(o1). dar va avea un comportament diferit. Object o) Object remove(Object cheie) Boolean containsKey(Object cheie) 84 . 3. Declaraţie metodă Operaţii de bază Semnificaţie Întoarce obiectul cu cheia transmisă ca parametru Inserează o legătură cheie-valoare Elimină legătura indicată de cheie Verifică existenţa cheii cheie în Map Object get(Object cheie) void put(Object cheie. Este de ajuns să utilizeze o variabilă interfaţă în care să memoreze referinţa la unul din cele două obiecte (Figura 10-5). nu contează ce obiect Java este utilizat pentru a reprezenta o colecţie şi dacă în mod succesiv. Într-un List. . În consecinţă. Variabilă de tip Collection a – implementare a lui Collection b. În acest mod. ArrayList. noua colecţie va fi iniţializată cu elementele colecţiei utilizată ca parametru. . dacă două obiecte a şi b implementează aceiaşi interfaţă. Utilizarea variabilelor interfaţă Interfaţa Map Map este o interfaţă care păstrează o asociere chei-valoare şi care permite căutări bazate pe chei. În continuare. va fi prezentat un scenariu posibil de utilizare a varaibilelor de tip Collection: 1. LinkedList. fără să necesite nici o modificare din parte clientului. elementele unice ale lui HashSet pot fi căutate în ordine şi poate accepta duplicate. 2. 2. construită pe baza lui colecţie: List lista = new ArrayList(colectie). Declarăm o variabilă colectie de tip Collection (poate fi un List sau un Set): Collection colectie. . se poate utiliza obiectul b în locul obiectului a. Se adaugă obiecte la colectie cu metoda add(): colectie. schimbând numai punctul de vedere. 3. lista conţine elementele din colec•ie memorate în HashSet. acest obiect este înlocuit cu un altul care implementează aceeaşi interfaţă. HashSet sau TreeSet: colectie = new HashSet().

getValue()).println(cheie + ": " + map.Entry are următoarele trei metode: Object getKey() Object getValue() Object setValue(Object val) Fiecare element din Set-ul de legături returnat de metoda entrySet()este văzut ca un element de tip Map.Entry) i. } } public class FreqHashMap { public static void main(String[] args) { HashMap ht = new HashMap().getKey() + ": " + e. public String toString() { return Integer. ) { Object cheie = i.Entry e = (Map. } Interfaţa Map are două implementări principale: HashMap şi TreeMap şi una moştenită din prima versiune de Java: Hashtable. Clasa HashMap Următorul exemplu verifică numerele aleatoare furnizate de metoda Math.keySet(). class Counter { //Obiectele acestei clase vor fi folosite ca numărători int i = 1. i.out.println(e. } Map.iterator().toString(i).Declaraţie metodă Semnificaţie Verifică existenţa valorii o în Map Returnează numărul de legături Verifică dacă mulţimea legăturilor este vidă sau nu Adaugă legăturile găsite în m Goleşte un Map Furnizează Set-ul tuturor legăturilor cheie-valoare Furnizeaza un Set compus din chei Furnizează o colecţie a tuturor valorilor din Map Boolean containsValue(Object o) Int size() Boolean isEmpty() Operaţii globale Boolean putAll(Map m) Void clear() Vederi ca colecţii Set entrySet() Set keySet() Collection values() Vederile (views) ale unui Map ne permit să utilizăm interfetele Collection (pentru valori) sau Set (pentru chei) pentru eleborarea întregului Map: for (Iterator i=map. i < 10000. //Produce un număr între //0 şi 19 inclusiv 85 .Entry este o interfaţă statică internă a lui Map care reprezintă toate legăturile cheievaloare din Map. putem parcurge o astfel de mulţime şi să afişăm fie cheia.random()*20)). System.iterator().get(cheie)). Acest lucru este realizat de următoarea secvenţă de cod: Map m=…//crearea unui obiect al unei clase ce implementează interfaţa Map for (Iterator i=m.util. ) { Map. System. fie valoarea fiecărei legături. i.hasNext().out.Entry. De aceea. import java.random().next(). Map.*.next(). i++) { Integer r = new Integer((int)(Math.hasNext().entrySet(). for(int i = 0.

else { int valoare = frecventa.containsKey(r)) ((Counter)ht. String header) list(PrintStream out) list(PrintWriter out) load(InputStream in) De exemplu. Map mapSortat = new TreeMap(map). if (frecventa==null) frecventa = unu.*. } } Clasa Properties Furnizează o colecţie persistentă de legături chei-valori in care cheile şi valorile sunt String-uri. String value) şi se poate obţine cu metoda overloaded getProperty(): String getProperty(String cheie) String getProperty(String cheie. n=args. for (int i=0.out.put(cheie.get(r)).util. System. Integer unu=new Integer(1). Din acest motiv. Implicit. clasa Properties furnizează următoarele metode instanţă: public public public public void void void void store(OutputStream out. frecventa = new Integer(valoare + 1). i++) { String cheie=args[i].out.put(r. } } Clasa TreeMap Clasa TreeMap furnizează o implementare a interfeţei Map în care colecţia de legături chei-valoare este ordonată după chei. valorile se numesc proprietăţi.get(cheie). O legătură cheie-proprietate este adăugată la un Properties cu metoda Object setProperty(String key.println(ht).length. } map. else ht.out. String proprietateImplicita) Persistenţa colecţiei permite memorarea şi încărcarea pe şi de pe suport persistent (sistem de fişiere). Următorul program ilustrează diferenţele dintre HashMap şi TreeMap: import java. În acest sens.println(map). implementând şi interfaţa SortedMap.intValue(). ordonarea este crescătoare (conform interfeţei Comparable).if(ht. System.size()+" cuvinte distincte gasite:"). memorarea într-un fişier a conţinutului unui obiect Properties se realizează prin următoarea secvenţă de cod: 86 . public class FreqTreeMap { public static void main(String args[]) { Map map=new HashMap(). new Counter()). } System. frecventa).out. dar criteriul de comparare poate fi specificat prin constructor: TreeMap (Comparator c) Alţi constructori: TreeMap () TreeMap (Map m) TreeMap (SortedMap m) Exemplu.println(map.println(mapSortat).i++. } System. Integer frecventa=(Integer)map. i<n.

next()).list(System. "Maria").add(sp). 250)). 1300)). public static Catalog getInstanta(){ if(c==null) c=new Catalog(). System. sp=c. return sp. if (sp!=null) add(sp).} public SpecificatieProdus getProdus(String nume){ Iterator it=iterator().equals(nume)) return sp.out. unde p este variabila referinţă din exemplul anterior. try{ p.util. if(sp.txt"). import java. while(it. while(it.println(e.println(sp). c.next(). SpecificatieProdus sp=null.getInstanta(). Exemplu. }catch(IOException e){System. p.getDenumire(). 87 .add(new SpecificatieProdus("Imprimanta".out. } sp=(SpecificatieProdus)osp.util. return c.add(new SpecificatieProdus("Calculator".store(new FileOutputStream("proprietati. c.Properties p=new Properties()..getMessage()). "Ioana"). System. } } } public class TestCatalog{ public static void main(String[] args){ Catalog c=Catalog. public class Catalog extends TreeSet{ private static Catalog c.setProperty("1". private OperatiiSpecificatiiProdus osp. } public void add(SpecificatieProdus sp){super.scrieObiect(it. } } import java.citesteObiect(nume). private Catalog(){osp=new OperatiiSpecificatiiProdus().hasNext()){ sp=(SpecificatieProdus)it. " Colectie de proprietati").*.setProperty("4". p. SpecificatieProdus sp=c.hasNext()) osp.} Ieşire: # Colectie de proprietati #Tue Jan 04 10:03:53 EET 2005 4=Maria 1=Ioana Colecţia de legături şi proprietăţi memorată într-un obiect Properties poate fi afişată şi pe ecran prin apelarea metodei list.out). } public void descarca(){ Iterator it=iterator().out.getProdus("Imprimanta").println(sp).*.getProdus("miere"). astfel: p.

private double total. ElementVanzare ev. this. sir+="Cumparator: "+c. while(it. 20)+formatare("Pret/articol".getNume()+" "+c. 25)+"\r\n". Vanzare v. sir+="-----------------------------------------------------------------------\r\n\r\n".LONG).import java. Calendar data.DAY_OF_WEEK)<=6)total=5*total/100. articole=v. 88 . ElementVanzare el. sir+=formatare("Denumire". return temp.format(data. c=v. total+=ev.get(Calendar.get(Calendar. if(cl.iterator(). --i) temp += " ".0. 15)+ formatare("Pret unitar".0. double t=v.c=c. } public ArrayList getProduse(){return this.getDateInstance(DateFormat.} public double calculeazaTotal(){ ListIterator li=listIterator().util.getProduse(). return total+calculeazaTVA().length(). Iterator it=articole.getInstance().*. } } import java.calculeazaCost().hasNext()){ public Factura(Vanzare v){ nrFactura=id++.} public Client getClient(){return c.hasNext()) { ev=(ElementVanzare)li. i>0. 15)+formatare("Cantitate". int latime) { String temp=sir. } public double calculeazaTVA(){return total*tva/100. public static int tva=20.next().getTime())+"\r\n" sir+="-----------------------------------------------------------------------\r\n\r\n".calculeazaTotal(). } public String toString(){ String sir="Factura: "+nrFactura+"\r\n".getPrenume()+"\r\n".public class Vanzare extends ArrayList{ private Client c. ArrayList articole. int nrFactura. } public String formatare(String sir.} public void addProdus(ElementVanzare ev){super. while(li. sir+="Data emiterii: "+ DateFormat.*.DAY_OF_WEEK)>=2&&cl.v=v. Client c. public Vanzare(Client c){this. data=Calendar.getClient(). for (int i=latime-sir.getInstance(). sir+="Adresa: "+c. public class Factura{ private private private private private private static int id=1. } Calendar cl=Calendar.getAdresa()+"\r\n".add(ev).text.

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

<H6>text</H6> Alinearea textului: <CENTER>text</CENTER> sau ca atribut: <H1 ALIGN=CENTER>text</H1> Trecerea pe linia următoare î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 căror 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 căror elemente sunt numerotate: introduce un element în listă 90 . Context pentru executarea applet-urilor Java.URI (Uniform Resource Identifier) sau URL..html sau . Un fişier HTML simplu Un tag poate avea modificatori. este de ajuns să fie salvat în format text cu extensia . Pagină Web = Document de text cu extensia . Utilizează protocolul HTTP. Identifică resursele utilizând adrese unice . Suportă plug-ins. Documentul poate fi scris cu word processor oarecare.html sau . Pagini Web Paginile Web sunt resurse Web care au o adresă URL (Uniform Resource Locator). .. Suport pentru orice mecanisme de scripting.htm al cărui conţinut va fi citit şi interpretat de un browser. Cere resurse de la server-ele din reţea.htm. Utilizează tag-uri (comenzi între < şi >) care au un înţeles bine precizat pentru browser.11. 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 secţiune: <H1>text</H1>. <H2>text</H2>. APPLET Browser – program cu urmatoarele functiuni: - vizualizează resursele codificate în HTML. HTML = Limbaj de comenzi cu care se scriu paginile Web. . Modificatorii sunt atribute.

precum si alte forme precum dreptunghiuri.Applet. Clasa Applet este un Container (componentă grafică Java utilizată pentru a include.<LI> text </OL> termină lista Linie de separare: <HR> Tag-ul APPLET <APPLET [ALT=TEXT] CODE=“NUMEAPPLET.magenta). Structura unui applet: 91 .CLASS] HEIGHT=ÎNĂLŢIMEA ÎN PIXELI [HSPACE=SPAŢIUL ORIZONTAL DINTRE APPLET ŞI TEXTUL CARE-L ÎNCONJOARĂ] WIDTH=LĂRGIMEA ÎN PIXELI [VSPACE=SPAŢIUL 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. 2.30). } } În pagina HTML: <applet name=”primul applet" width=”100” height="60”> </applet> code=”PrimulApplet.awt. browser-ul execută următorii paşi: 1. linii poligonale.} public void paint(Graphics g){ g. aceasta descarcare este realizata de browser.CLASS” [CODEBASE=URL-UL FIŞIERULUI . 4.drawString(“Buna ziua!”. Cere executarea metodelor standard implementate în applet: init.prezinta utilizatorului o interfaţă grafică şi poate capta evenimente declanşate de utilizatori. Alocă aria în care se vizualizează applet-ul. cercuri. public class PrimulApplet extends Applet { public void init(){setBackground(Color. un applet are urmatoarele proprietati: .*.applet sau clasa JApplet a pachetului javax.swing. Orice applet este un obiect al unei clase definită de utilizator care extinde clasa Applet a pachetului java. Exemplu: import java. 3. paint etc.funcţioneaza ca parte integrantă a unui browser. gestiona şi vizualiza alte componente grafice) care utilizează metoda paint pentru vizualizarea desenelor şi componentelor grafice pe o suprafaţă dreptunghiulară. elipse.20.class din directorul classes al directorului curent. Incarcă fişierul PrimulApplet.class” codebase=”classes" Când întâlneşte tag-ul APPLET. putem desena caractere de un anumit font si o anumita culoare. import java. . Asadar. Instanţiază clasa PrimulApplet. apare intr-o fereastra a broser-ului ca un dreptunghi (panel-panou) in care avem o prezentare grafica cu un fond (background).applet.

awt..paint(Graphics g).applet. un fond de o anumită culoare sau o imagine. browser-ul cheamă 2. class NumeApplet extends Applet{ void init(){…} void start(){…} void stop(){…} void destroy(){…} void paint(Graphics g){…}//mostenita din supraclasa Container Browser 1. . Browser-ul lansează pagina şi cheamă stop() applet-ul se opreşte din rulare 5.import public public public public public public } java. 92 .parametrul g este iniţializat cu un obiect al clasei Graphics care este creat şi transmis lui paint() de către browser.. În aceste metode trebuie să descriem cum trasăm în dreptunghiul applet-ului un text. repaint() şi update(Graphics g) sunt utilizate pentru desenarea pe un Container. . Applet-ul a fost încărcat în sistem şi iniţializat Browser-ul cheamă init() start() applet-ul rulează… paint() apoi cheamă 3. în particular într-un applet vizualizat în pagina HTML.Applet. vizualizează întreaga pagină 4. Pentru a putea utiliza metoda paint() trebuie importată clasa Graphics din pachetul java. Accesează pagina care conţine un applet Applet Cere încărcarea applet-ului Applet-ul este încărcat în sistem Pentru a-l iniţializa. Acest obiectul reprezintă contextul grafic al applet-ului.. .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 } . o linie. Browser-ul revine în pagina applet-ului sau browser-ul eliberează definitiv pagina conţinută 6.. va fi apelată metoda destroy() Desenarea cu paint() .

awt.clip-ul curent.culoarea curentă. Întoarce dimensiunilr tipului de font specificat. ImgObs) drawLine(int. int) drawOval(int.coordonatele originii translatării pentru desenat şi pentru operaţia de clipping. 40. Cine furnizează obiecte Graphics? Obiectele Graphics sunt întoarse de metodele getGraphics() existente în clasele Component.font-ul curent. int. int. Pune originea contextului grafic în punctul (x. Color. y) al sistemului curent de coordonate. . Întoarce font-ul curent.fillRect (10. g. Image şi PrintJob. bază pentru toate contextele grafice care aparţin unei aplicaţii de desenat.applet. Trasează o secvenţă de linii conexe specificate de array-urile de coordonate x si y. int) draw3DRect(int. 20. g. public class Dreptunghiuri extends Applet{ public void paint(Graphics g) { g.Applet. . int[]. 35). 15. int. Desenează o linie între două puncte ale sistemului de coordonate al contextului grafic.Color. . Trasează un poligon definit de doua array-uri de puncte x şi y.awt.obiectul Component pe care se desenează (un applet. Desenează atâta cât din imagine specificată este disponibilă. Întoarce dimensiunile tipului curent de font. int) drawImage(Image. int. 30). 0. int) drawPolyline(int[]. int) Semnificaţie Elimină contextul grafic. g.setColor(new Color(0. . 65). Cele mai importante metode ale clasei Graphics sunt prezentate în tabelul urm.translate(20. Când acelaşi applet trebuie să fie redesenat (de exemplu când am schimbat culoarea fondului cu setBackground()). int. Desenează un arc înscris în dreptunghiul specificat. int. int. import java.Metoda paint() va fi apelată automat de către browser când se desenează în applet. int[]. se utilizează repaint(). Metoda dispose() getColor() setColor(Color) getFont() setFont(Font) getFontMetrics() getFontMetrics(Font) translate(int. 255)). 15. boolean) drawArc(int. . Setează font-ul contextului curent ca fiind font-ul specificat. Trasează o elipsă în interiorul dreptunghiului specificat. int. int. int. import java. int. Informaţiile de stare necesare pentru desenarea în Java sunt: .Graphics. Un applet care desenează import java. Setează culoarea curentă ca fiind culoarea specificată.drawRect (10. int. int. } } Graphics Graphics = Clasă abstractă. Desenează un dreptunghi în 3-D. Întoarce culoarea curentă. de exemplu).funcţia logică curentă a operaţiei în pixeli (XOR sau Paint). Fiecare pereche 93 . int) drawPolygon(int[].

Font f) int getSize() int getStyle() boolean isBold() boolean isItalic() boolean isPlain() static final int BOLD=1. int stil. fillRect(int. Color. int dim) Font f=new Font(“SansSerif”.setFont(Font f) Applet pentru ora exactă 94 . int. Exemple de font-uri din JDK 1. fillRoundRect(int. int[]. Color Color este o clasă care reprezintă o culoare.4.Metoda Semnificaţie (x[i]. fillPolygon(int[]. int) culoarea curentă. int. fillArc(int. xxx alpha) rgb) rgb. Color. Helvetica. xxx b) r. int. Color. int. int) specificate. Font static Font getFont(String nm)//returneaza un obiect de tip Font cu numele specificat static Font getFont(String nm. int.green.1: Dialog. xxx g. static final int PLAIN=0.white. xxx b. int) Desenează şirul specificat cu culoarea contextului grafic curent. int. DialogInput.red. Umple dreptunghiul cu colţuri rotunde specificat cu int.blue. Serif. int) Umple dreptunghiul specificat cu culoarea curentă. boolean hasAlpha) Color. int) Umple cu culoarea curentă un poligon definit de două array-uri de coordonate x şi y. int. int. drawString(String. SansSerif. int) Trasează dreptunghiul specificat. y[i]) defineşte un punct.BOLD. int) Setează clip-ul curent dreptunghiul specificat cu coordonatele date ca parametri actuali ai metodei.yellow. int. int. int. TimesRoman. int. int. int. Se poate impune unui context grafic un font nou astfel: void Graphics. Umple un sector de cerc continut in dreptunghiul int) specificat cu culoarea curenta. int. static final int ITALIC=2. drawRoundRect(int.12). drawRect(int. Shape getClip() Întoarce aria de lucru curentă ca un obiect de tip interfata Shape getClipBounds() Intoarce dreptunghiul circumscris ariei de lucru. int. Monospaced. Colorează interiorul dreptunghiului 3D cu culoarea boolean) curentă. Color.magenta etc Color.cyan. int) Umple cu culoarea curentă o elipsă continută în dreptunghiul specificat. int. setClip(int. fillOval(int. xxx=int sau float Clasa Color conţine câmpuri constante iniţializate cu culori fundamentale: Color. Trasează un dreptunghi cu colţurile rotunjite int. fill3DRect(int. int. Dimensiunile sunt specificate în puncte tipografice (1/72”): Font (String nume. int. xxx g. int. Culorile pot fi construite cu constructori ca: Color Color Color Color (xxx (xxx (int (int r. int. int.Font.

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

". int w3 = fm. FontMetrics fm=g.top.stringWidth(s1).width-in.Font. public void setFonts(Graphics g){ if (fontsSet) return. String s3 = " testarea font-urilor. int clientHeight =d. cx=fm.14).drawString(s1. cx += w1.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”. cy).setFont(f). String s1 = "Acesta este". fim=g. 96 .top.getFontMetrics(Font) FontMetrics Toolkit.BOLD+Font. int cy=clientHeight/2+in.right-in. Dimension d = getSize().int off.left.Font. fi=new Font("SansSerif". int w2 = fim. Insets in = getInsets(). private FontMetrics fm. private boolean fontsSet = false.getFontMetrics() FontMetrics Graphics.height-in. Font. g.bottom-in. int cx=(clientWidth-w1-w2-w3)/2 + in.top.stringWidth(“Un şir lung de 31 de caractere. clientHeight-1).ITALIC. int w1 = fm.BOLD + Font.”).stringWidth(s2).ITALIC.getFontMetrics(f).int len) int bytesWidth(byte data[].FontMetrics Component. String s2 = " un program pentru".left.left. private FontMetrics fim. g.drawRect(in.getFontMetrics(Font) int charsWidth(char data[].int off. g.in.getFontMetrics(f). fm=g.getFontMetrics(Font) FontMetrics Graphics. fontsSet = true. 14). cx.BOLD. f=new Font("SansSerif". public class TestFont2 extends Frame{ private Font f. } public void paint(Graphics g){ setFonts(g). int clientWidth=d. Programarea cu obiecte Font Exercitiu. private Font fi. Cum să scriem textul: Acesta este un program pentru testarea font-urilor poziţionat în mijlocul unui frame utilizând două font-uri diferite? Solutia o gasiti în Programul 2.getFontMetrics(fi).stringWidth(s3).clientWidth-1. 12).

TestFont2: Utilizarea lui Font şi FontMetrics 97 . g.setFont(fi). cx. } } Programul 2.show().setFont(f). cy). cx. g. } public static void main(String args[]){ Frame f = new TestFont2(). cx += w2. f.g.drawString(s3. g. cy).drawString(s2.

Unei componente i se asociază următoarele elemente: . INTERFETE GRAFICE AWT-Abstract Window Toolkit Serie completă de componente ale interfeţei grafice utilizator (GUI) Suport pntru “container-e” de componente grafice.dimensiune . Mecanisme pentru aranjare a componentelor într-un mod care permite obţinerea unui GUI independent de platformă. independent de al altora. Gestionează ferestrele. exceptând menu-urile. Grafica .Desenează figuri în 2D personalizate .un container părinte .Umple figurile cu culori şi modele Container-e Ideea fundamentală: O fereastră Java este un container care conţine o colecţie de componente încuibate. Fiecare componentă are ciclul său de viaţă.un peer nativ .12.Component java.font şi dimensiunile font-ului (font metrics) 98 .Controlează font-urile Java 2D API - Posibilitatea de grafică mai laborioasă . Applet = Container de componente grafice care poate fi executat de un browser.awt. Container-ele sunt gestori ai componentelor conţinute. Un mecanism de evenimente care gestionează evenimentele sistemului şi evenimentele utilizatorului. Frame = Fereastra de nivel cel mai înalt într-o aplicaţie.Desenează figuri în 2D .Controlează culorile .localizare .un obiect Graphics . Ierarhia claselor AWT Object Component Canvas Container List Button TextComponent CheckBox ScrollBar Label Choice Panel Window TextField TextArea Applet Frame Dialog FileDialog java. Ierarhia de container-e poate avea orice nivel de complexitate.Component = Clasă abstractă care generalizează toate componentele AWT. menu-urile şi ferestrele de dialog.awt.

//adauga TextField-ul la fereastra buton1=new Button ("Apasa").//declara doua Button public void init(){ text = new TextField(20).awt. Component c) Component getComponentAt(int x.- culori pentru foreground şi background specific lingvistic dimensiuni maxime şi minime Component⇒Container ⇒Window⇒Frame java. //creaza un Button add(buton2).applet.// importa toate clasele AWT public class Primul extends Applet { TextField text. //adauga Button-ul la fereastra } } 99 . buton2.Container Component add(Component c) Component add(String name.//adauga Button-ul la fereastra buton2=new Button("Cancel").*.//creaza un Button add(buton1). 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.Window void toFront() void toBack() Toolkit getToolkit() void show() java.Applet. bg Point getLocationOnScreen() Color 2 Graphics getGraphics() void setBackground(Color c) Graphics void setForeground(Color c) 1 Dimension getSize() void setSize(int w. import java.//declara campul de text ca TextField Button buton1. int h) * void setSize(Dimension d) java. int y) 1 void setLocation(Point p) +fg.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 Adăugarea componentelor grafice import java.awt.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.awt.//creaza un TextField add(text).

c. c1=new Checkbox(“Primul”.HORIZONTAL. public class Container5 extends Applet { Scrollbar hSB. add(c).40).awt. Canvas şi Label import java. import java. } } } import java. un grup de TextField text2. text2=new TextField(“Buna”. text1=new TextField(“Ion Pop”. add(list1).Applet. public class Container1 extends Applet{ public class Container3 extends Applet{ TextField text1. add(hSB). import java. public void init(){ Etichetă add(etic).Applet.setState(false). public class ContainerX extends Applet{ public class Container2 extends Applet{ //declaratii/alocari de componente TextArea tArea.20). O arie de text public void init() { //declaratii/alocari de componente public void init() { //adaugarea componentelor in applet tArea=new TextArea(10.applet.VERTICAL.applet.TextArea. Checkbox c1.*.awt. Canvas public void init() { c=new Canvas(). list1.10). MenuComponent MenuBar MenuItem Menu PopupMenu CheckboxMenuItem 100 .Applet.addItem(“Rosu”). import java. c2.setCheckboxGroup(cBG).addItem(“Verde”). 100).cBG.applet.Applet.Applet.Applet.1. } } import java.*.*.setBackground(Color. 1.awt.1.awt . c2: public void init() { public void init() { butoane radio text1=new TextField(20). public class Container4 extends Applet{ List list1. list1.applet.0. } add(c2).awt. true).*. } } import java. } } List. add(text2). import java.addItem(“Albastru”). import java. c. public class Container6 extends Applet{ Label etic=new Label(“Nume si Prenume”).awt. public class Container7 extends Applet{ Canvas c. import java.0.*. } } Menu In Diagrama 1 se prezinta conceptele principale pe care trebuie sa le cunoastem pentru a programa menu-uri cu java. import java. c2=new Checkbox(“AlDoilea”).*. import java. vSB=new Scrollbar(Scrollbar. Bare de defilare public void init(){ verticală şi orizontală hSB=new Scrollbar(Scrollbar.applet. Lista public void init(){ list1=new List(2. CheckboxGroup cBG=new CheckboxGroup().applet. add(text1). } add(tArea).applet.100).black). list1. add(c1).20).applet. true).1.Applet. } c2.resize(40. import java.awt. TextField şi Checkbox import java.*. vSB.Applet. Scrollbar. add(vSB).awt.awt. } } import java. add(text1). import java.*.

add(editUndo). MenuItem editCut=new MenuItem(“Cut”).Diagrama 2.setHelpMenu(helpMenu). helpMenu. editCopy. setSize(new Dimension(400. MenuItem fileExit=new MenuItem(“Iesire”). MenuItem editUndo=new MenuItem(“Cancel”). public class MenuFrame extends Frame { MenuItem fileNew=new MenuItem(“Nou”). } public static void main(String[] args){ MenuFrame meu=new MenuFrame(). editUndo.add(editPaste). editMenu.setEnabled(false). Ierarhia componentelor de menu Din Programul 3 se poate vedea care este în esenta modalitatea de programare a menu-urilor. helpMenu..addSeparator(). MenuItem editCopy=new MenuItem(“Copy”). menubar.add(helpAbout). MenuItem fileSave=new MenuItem(“Salveaza”). editCut. editMenu. menubar.add(fileOpen).add(editCopy).add(editMenu). MenuBar menubar=new MenuBar(). } } Programul 3. fileMenu. editMenu. MenuItem helpAbout=new MenuItem(“Info.”). MenuFrame: Programarea menu-urilor Grafica cu LayoutManager Layout Manager = Interfaţă utilizată pentru asezarea diferitelor componente într-un container după un şablon de aranjare.. MenuItem helpContents=new MenuItem(“Rezumat”).300)). helpMenu.addSeparator().add(fileExit). LayoutManager2 extinde LayoutManager şi este folosit pentru asocierea de constrângeri aşezării componentelor.add(helpContents). Menu editMenu=new Menu(“Modifica”). MenuItem editPaste=new MenuItem(“Paste”).*.setEnabled(false). public MenuFrame() { super(“Exemplu de menu”).add(fileNew). Menu helpMenu=new Menu(“?”).setEnabled(false).add(helpMenu). editPaste.add(fileMenu).add(editCut). import java. editMenu.addSeparator(). fileMenu. Menu fileMenu=new Menu(“Fisier”).setEnabled(false). MenuItem fileOpen=new MenuItem(“Deschide”). menubar. editMenu. show(). fileSave.awt. 101 . menubar. fileMenu. fileMenu.setEnabled(false). fileMenu.add(fileSave). setMenuBar(menubar).

awt. panel. Exemplu.printF. Acest layout este util căn o aceeaşi suprafaţă trebuie partajată de mai multe paneluri care trebuie să fie vizualizate în momente diferite de timp. addComponent(cancel. Fiecare obiect GridBagLayout păstrează o grilă dreptunghiulară dinamică de celule în care fiecare componentă ocupă una sau mai multe celule.NORTH. fără să fie nevoie ca componetele să aibă aceleaşi dimensiuni. addComponent(print. private Factura factura.0.1. printF=new Button("PrintToFile").1. setLayout(new FlowLayout()). AppletViewer: GestoreLayout Applet setLayout(new GridLayout(3.20.1. GridLayout. public FacturaFrame(Factura f) {super("Factura"). 50).1). AppletViewer: GestoreLayout Applet setLayout(new BorderLayout()). precum cărţile într-un pachet de cărti.1. factura=f. addComponent(arie. CardLayout aşează componentele (de obicei paneluri) în straturi. cancel.anchor=GridBagConstraints.1).1.setEditable(false). private GridBagLayout gb. este vizibilă numai o componentă.1).HORIZONTAL. arhivare=new Button("Arhivare"). BorderLayout.1.1.toString().2)).0.1. gbc. import java. gbc. gb=new GridBagLayout().fill=GridBagConstraints. dar componentele pot fi “răsfoite” şi să controlăm care din ele să devină vizibilă. În orice moment.5). GridBagLayout. Panel panel. CardLayout. public class FacturaFrame extends Frame {Button print.3. print=new Button("Print").2.*. addComponent(arhivare. care formează aria de vizualizare a componentei.setLayout(gb).1. cancel=new Button("Cancel").4.arhivare. 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ă. arie.Cele mai folosite clase de gestori de layout care implementează interfaţa LayoutManager sunt: FlowLayout. TextArea arie. panel=new Panel(). arie=new TextArea(factura.1. addComponent(printF. private GridBagConstraints gbc.1). 102 . gbc=new GridBagConstraints().

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

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

nativa (1). ci in fereastra container-ului lor greu (2). opaca. De aceea.add(new JButton(“Buton”)).*.implementeaza o arie dreptunghiulara in fereastra browser-ului . componentele usoare pot avea background-uri transparente. container. JFrame public class Fereastra extends JFrame{ public Fereastra(){ Container container=getContentPane(). adica o subclasa a clasei java.Container. BorderLayout.JApplet. Swing este o multime de componente usoare aflate in pachetul javax.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 .NORTH).JWindow – o fereastra externa. PROGRAMAREA INTERFETELOR GRAFICE CU SWING Swing este un tehnologie API care extinde AWT-ul pentru construirea interfetelor grafice. are un rol dublu: este un simplu container si un canvas pentru afisarea graficelor. panel.14. panel.add(new JLabel(“Label”)). Din (1) rezulta ca. } } Content pane JPanel JButton JLabel Container-e usoare: 1. JRootPane – este continut in orice container greu.JFrame – implementeaza o fereastra principala. JPanel panel=new JPanel(). 2. . Aproape toate componentele Swing-ului sunt usoare. .awt. exceptiile sunt container-ele de nivel inalt: .add(panel. . JPanel – succesorul lui Panel si Canvas.swing. Spre deosebire de componentele grele nu sunt incadrate intr-o fereastra (window) proprie.JDialog – implementeaza o fereastra secundara Din (2) rezulta ca componentele usoare trebuie sa stea in ultima instanta intr-un container greu.

getFontMetrics().Exemplu. f. Straturile cu valori mai mari sunt plasate deasupra straturilor cu valori mai mici.gif")).addActionListener(this). li).height.stringWidth(sir). import java. c<d.setSize(200. f.event. } public void paintComponent(Graphics g){ String sir="Buna ziua". li<d.blue). li+=i) for (int c=0. 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 java. new ImageIcon("swing. }}).*.add(buton).swing.drawString(sir.setDefaultCloseOperation(JFrame. g. } } 3.awt.setVisible(true).setVisible(true). public class Prob1 extends ActionListener { private Component panelSticla.awt. import javax. FontMetrics f=g. unde bar menu-ul si content pane sunt asezate DEFAULT_LAYER 0 Implicit. c+=l) g. } public void actionPerformed(ActionEvent e){ panelSticla. addMouseListener(new MouseAdapter(){ public void mousePressed(MouseEvent e){ setVisible(false). int l=f. for (int li=i. buton.setColor(Color. } public static void main(String[] arg){ JFrame f=new Prob1().getHeight(). 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. buton=new JButton("". public Prob1(){ panelSticla=new PanelSticla(). Dimension d= getSize().200). Plasarea componentelor poate fi controlata si in cadrul unui acelasi strat prin urmatoarele 106 . c. private JButton buton. f. int i=f. Container content=getContentPane(). }} JFrame implements class PanelSticla extends JPanel{ public PanelSticla(){ setOpaque(false).*.*.width. JLayeredPane –nu are un layout manager implicit si permite plasarea componentelor pe diferite straturi: Strat Valoare Descriere FRAME_CONTENT_LAYER -3000 Stratul de baza.EXIT_ON_CLOSE). content.small. setGlassPane(panelSticla).

import java. public Prob2(){ lp=new JLayeredPane(). tp. panel2. new ImageIcon("ok.add(new JButton("buton in panelul 2")).setText(sir).MODAL_LAYER. "Primul panel"). new JButton("Default1").addTab("Al doilea panel".*.gif"). JLayeredPane. import javax. "Panelul 2"). i++){ String sir=butoane[i]. for(int i=0. private JButton[] butoane={ new JButton("Frame content"). JLayeredPane. 350.add(new JButton("buton in panelul 1")). new JButton("Default0").DEFAULT_LAYER. straturi[i]. Descriere Indexul intr-un vector de componente pastrat de panelul stratificat.add(tp).PALETTE_LAYER.event.awt. public class Prob3 extends JFrame{ private JTabbedPane tp.length.*.DEFAULT_LAYER.}} public class Prob2 extends JFrame{ private JLayeredPane lp. Componentele cu pozitii mai mici sunt afisate deasupra celor cu pozitii mai mari. JLayeredPane. new JButton("Modal").equals("Default0")) lp.exit(0).awt. i++){ lp.FRAME_CONTENT_LAYER.setVisible(true).POPUP_LAYER. 107 .setSize(600.*. new JButton("Popup").480). 0). private Integer[] straturi={ JLayeredPane.add(panel1.DRAG_LAYER }. panel1.length. Exemplu3.*. butoane[i].setPosition(butoane[i]. } for(int i=0.getText()+"-"+lp. lp. butoane[i]. f. JPanel panel2=new JPanel(). new JButton("Palette").proprietati: Proprietate Index -getIndexOf(comp) Strat -getLayer(comp) Pozitie -getPosition(comp) Exemplu2. Componentele de pe un strat cu numar mai mic sunt afisate sub componentele ce se afla pe straturi cu numar mai mare. panel2.*. Indicele are legatura cu ordinea componentelor: cele cu indice mai mic sunt plasate deasupra celor cu indice mai mare. setContentPane(lp). if (sir. else if (sir. JLayeredPane.}}). 4. import javax. Pozitia unei componente relativa la celelalte componente din acelasi strat.setLayer(butoane[i]. import java.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){System. f.swing.swing. sir=butoane[i].getPosition(butoane[i]).setBounds(i*50. f. JPanel panel1=new JPanel(). tp.getText(). } Container contentPane=getContentPane(). JTabbedPane – panel ce contine pagini (tab-uri) de paneluri.add(butoane[i]).setPosition(butoane[i]. new JButton("Drag") }. i*50. 75). 1).awt.intValue()). contentPane. Stratul pe care se afla componenta respectiva. Fereastra cu 2 pagini de panel-uri de contin cate un buton. import java. JLayeredPane. } } public static void main(String[] arg){ JFrame f=new Prob2(). public Prob3(){ tp=new JTabbedPane().event. JLayeredPane. i<butoane. i<butoane.equals("Default1")) lp.

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

intr-un alt container Swing. redimensionare).clasa JInternalFrame. Daca este maximizata nu poate fi redimensionata rootPane JRootPane SG JRootPane Panelul radacina asociat ferestrei 1 C-poate apare in constructor. care stau pe desktop -clasa JDesktopPane. G-getter 109 . S-setter.interne deoarece stau. minimizare. 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. iconificare. Ferestrele interne sunt: . fiind componente usoare. de obicei un desktop pane.ferestre deoarece furnizeaza multe din caracteristicile unei ferestre (inchidere.FERESTRE INTERNE Swing ofera functionalitate MDI (Multiple Documente Interface) prin ferestre interne. . maximizare.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. 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. deschidere.

setLayout(new FlowLayout()). contentPane. /*Container content=fi.container-ele usoare JViewport si JScrollPane (inlocuieste si imbogateste componenta grea AWT ScrollPane) .150)).NORTH).add(new JLabel(new ImageIcon("swing. fi.pentru a muta vederea la stanga: crestem coordonata X a vederii . Pentru aceasta putem folosi urmatoarele clase: .setFrameIcon(new ImageIcon("ok. dp.small. BorderLayout.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. private JInternalFrame fi.pentru a muta vederea in sus: crestem coordonata Y a vederii . 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.revalidate(). BorderLayout. dp=new JDesktopPane(). true). 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 - .CENTER). public Prob1(){ Container contentPane=getContentPane().add(buton. dp.add(dp. JPanel p=new JPanel().add(fi). imagini.} boolean SG false Scroll-area componentelor Este necesara in cazul in care o componenta (tabele. buton.setVisible(true).add(p). fi. private JButton buton.getContentPane(). true. liste) este mai mare decat spatiul de afisare. texte.true. } public void actionPerformed(ActionEvent e){ fi=new JInternalFrame("O noua fereastra interna".setPreferredSize(new Dimension(250. p.*/ dp.selected Selecteaza sau deselecteaza fereastra interna title String C1S null Titlul afisat in bara de titlu al G ferestrei Exemplul 1.addActionListener(this). contentPane. L_MOD BACKINGSTORE_SCROLL_MODE. //fi. content. Pozitia vederii poate fi manevrata pentru a afisa regiuni diferite ale vederii astfel: . trees. true.interfata Scrollable .gif")).pentru a muta vederea in jos: descrestem coordonata Y a vederii . buton=new JButton("creaza Frame").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.gif"))).

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

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. 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.LOWER_RIGHT_COR NER Scrollbar-ul orizontal folosit de panel Politica folosita pentru detrminaea circumstantelor in care scrollbar-ul orizontal este afisat.container uşor ce contine un viewport cu scrollbar-uri si header-e de coloane si linie optionale.LOWER_LEFT_CORN ER ScrollPaneConstants. Constante: ScrollPaneConstants.HORI AR_AS_NEEDED ZONTA ScrollPaneConstants.UPPER_RIGHT_CORN ER ScrollPaneConstants.UPPER_LEFT_CORNE R ScrollPaneConstants.JSCROLLPANE .VERTICAL_SCROLLB ne.VERTICAL_SCROLLB 112 .HORIZONTAL_SCRO LLBAR_AS_NEEDED 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.HORIZONTAL_SCRO LLBAR_NEVER ScrollPaneConstants.

113 .gif"))). sp. sp. contentPane.add(new JLabel(new ImageIcon("setup. obiectiv. obiectiv=new JViewport().setColumnHeaderView(new JLabel(new ImageIcon("sus. titlu.setBorder(Border) Tipuri de bordura Tip de bordura Descriere Opaca Constante asociate Bevel O Bordura 3D da RAISED. pot fi incadrate cu o bordura prin executarea a doi pasi: . JPanel p=new JPanel(). sp=new JScrollPane(obiectiv).viewport viewportBorder viewportView Exemplul 5.UPPER_RIGHT_CORNER. } Borduri . obiectiv.setScrollMode(JViewport. Pozitia ABOVE_TOP.setCorner(ScrollPaneConstants. TOP. new JLabel(new ImageIcon("palette_hand. 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. .addMouseMotionListener(listener). obiectiv.add(sp. listener=new DragListener(obiectiv).border. obiectiv.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().construim tipul de bordura dorit.setView(p).addMouseListener(listener). BorderLayout.* Toate componentele (de tip JComponent) cu exceptia lui JViewport.gif"))). LOWERED Titled O bordura cu nu DEFAULT_POSITION.il transmitem cu metoda JComponent. p.BACKINGSTORE_SCROLL_MODE).pachetul javax. JViewport Border Component SG SG CSG L_SCRO LLBAR_ AS_NEE DED JViewpo rt null null AR_NEVER ScrollPaneConstants.gif"))).CENTER).swing.

DEFAULT_JUSTIFICATION. LEFT. BOTTOM. ABOVE_BOTTOM. CENTER.titlului poate fi setata BELOW_TOP. RIGHT Ierarhia claselor Border <<Interface>> Border AbstractBorder BevelBorder CompoundBorder EmptyBorder EtchedBorder MatteBorder LineBorder TitledBorder 114 . BELLOW_BOTTOM.

LOWERED))).getClass(). JFrame f=new JFrame(). import java.*.CENTER). return jp.*. add(showBorder(new TitledBorder("Titlul meu"))). 4)).setBorder(b). Border b2=BorderFactory. f. } public Prob6() { setLayout(new GridLayout(2. add(showBorder(new EtchedBorder())).contine metode statice de construire a bordurilor ce vor fi partajate de componente.awt. add(showBorder(new MatteBorder(5.swing.setSize(300.awt.300).swing.Exemplul 6.toString().swing. atunci conditia (b1= =b2) intoarce true.createRaisedBevelBorder().blue))).event. jp.Color.setVisible(true). add(showBorder(new CompoundBorder( new EtchedBorder(). public class Prob6 extends JPanel { static JPanel showBorder(Border b) { JPanel jp = new JPanel(). De exp: Border b1=BorderFactory. add(showBorder(new SoftBevelBorder(BevelBorder.add(new JLabel( nm.CENTER).getContentPane().*.RAISED))).DISPOSE_ON_CLOSE). BorderLayout.substring(nm. import java.border. String nm = b. new LineBorder(Color. nm=nm.5.este in pachetul javax.*. f. deci utilizarea este mai eficienta. jp.magenta))).setLayout(new BorderLayout()).30. f. } public static void main(String args[]) { JPanel p=new Prob6().30.add(p). }} Clasa BorderFactory .setDefaultCloseOperation(WindowConstants. 115 .lastIndexOf(". import javax. import javax. jp.red)))).createRaisedBevelBorder(). f. JLabel.* . add(showBorder(new BevelBorder(BevelBorder. add(showBorder(new LineBorder(Color.")+1).

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

Sign up to vote on this title
UsefulNot useful