PROGRAMARE IN JAVA - Note de curs

1

Curs 1
Introducere
Incepand cu anul 1977 incepe utilizarea pe scara larga a calculatoarelor personale, pretul acestora facandu-le accesibile tuturor. In 1981 IBM, cel mai mare producator de computere, lanseaza pe piata modelul sau de calculator personal – IBM PC (XT). Aproape peste noapte calculatoarele personale patrund in intreprinderi, organizatii si chiar in casele oamenilor. Initial aceste calculatoare erau folosite ca unitati independente, transferul informatiilor de la un calculator la altul se facea prin intermediul dischetelor. Pentru a eficientiza schimbul informatiilor intre calculatoarele personale acestea au fost interconectate fie prin legaturi telefonice fie in retele locale in cadrul aceleiasi cladiri (LANs – local area networks). Aceasta a dus la raspandirea aplicatiilor de calcul distribuit (distributed computing). In loc de a fi adunate si prelucrate centralizat, intr-un centru de calcul dotat cu calculatoare foarte performante, datele se procesau distribuit, pe calculatoare personale conectate in retea, amplasate in locurile in care informatia era obtinuta. Puterea de calcul a unui PC era suficienta pentru a asigura cerintele unui utilizator individual si comunicatia in retea. La ora actuala un PC de 1000$ are o putere de calcul impresionanta, fiind la fel de performant ca un calculator mare din anii 70, avand pretul de un milion de dolari. Informatia este distribuita prin retea unde unele calculatoare numite file servere au sarcina principala de a stoca programe si date iar altele numite clienti apeleaza la serviciile serverelor pentru a accesa si procesa distribuit aceste date. Prelucrarea distribuita a datelor presupune “cooperarea” intre aplicatiile executate pe calculatoarele client si cele executate de servere. Aplicatia client solicita un anumit serviciu aplicatiei server, aceasta din urma efectueaza prelucrarile necesare satisfacerii cererii clientului si ii transmite rezultatele solicitate. O aplicatie data de prelucrare distribuita consta nu dintr-un singur program executat pe un singur calculator ci din mai multe programe executate pe doua sau mai multe calculatoare interconectate in retea. O astfel de aplicatie se numeste aplicatie client/server. In anii 70 si 80 limbajele de programare uzuale in elaborarea sistemelor de operare si a aplicatiilor client /server de prelucrare distribuita in retea erau C si C++. Odata cu interconectarea retelelor locale LAN in retele WAN (wide area network) si dezvoltarea tehnologiilor Internet, limbajul de programare Java castiga rapid teren oferind perspective noi pentru dezvoltarea aplicatiilor bazate pe aceste tehnologii.

Limbaje masina, limbaje de asamblare, limbaje de nivel inalt
Fiecare calculator “intelege” doar limbajul de programare specific procesorului cu care este prevazut. Acest limbaj “natural’ care consta dintr-un “vocabular” restrans de comenzi si un set de reguli sintactice de utilizare a comenzilor se numeste limbaj

2

CURS 1

masina. Fiecare comanda este reprezentata printr-un numar. Operanzii comenzii sunt si ele numere reprezentand fie valori ale datelor prelucrate de comanda fie registrul sau adresa locatiei de memorie in care datele prelucrate se afla sau unde va fi depus rezultatul. O instructiune masina ce poate fi executata de procesor consta deci din numarul asociat comenzii urmat eventual de numere desemnand operanzii comenzii. Programul masina consta dintr-o succesiune de instructiuni masina a caror executie duce la prelucrarea dorita a datelor initiale si obtinerea rezultatelor. Acest program masina, constand deci dintr-un sir de numere – cod si date, se poate incarca sub forma binara in memoria calculatorului si executat. Este evident ca un program masina nu poate fi executat decat pe un calculator dotat cu procesorul al carui set de comenzi a fost folosit la scrierea programului. Spunem deci ca programul masina nu este portabil fiind dependent de masina. Odata cu raspandirea calculatoarelor cererea tot mai mare de aplicatii programarea direct in limbaj masina a devenit ineficienta fiind prea greoaie. Din acest motiv, pentru a facilita elaborarea programelor, fiecarei comenzi elementare (numar) a procesorului i s-a asociat o succesiune de litere reprezentand abrevierea din limba engleza a comenzii respective. De exemplu pentru comanda de adunare s-a folosit mnemonica ADD (abreviere de la addition). Folosind mnemonicile programele puteau fi concepute, intelese, corectate si modificate mai usor. Setul de mnemonici ale comenzilor si regulile de constructie a instructiunilor constitue asa numitul limbaj de asamblare. Un program scris in limbaj de asamblare nu poate fi executat direct de calculator. Desi inteligibil pentru om, el nu poate fi “inteles” de calculator care asa cum am vazut “intelege” numai limbajul masina al procesorului cu care este echipat. In aceste conditii programul scris in limbaj de asamblare, pentru a putea fi executat, trebuie in prealabil “tradus” in limbaj masina. Aceasta “traducere” este o operatie de rutina prin care fiecare mnemonica a unei comenzi este substituita cu codul masina asociat. Fiind o operatie de rutina, aceasta “traducere” poate fi realizata automat de un program de calculator numit asamblor. Ca si programele masina, programele scrise in limbaj de asamblare se adreseaza unui anumit procesor. Fiecare tip de procesor are propriul sau set de comenzi masina si deci si propriul sau limbaj de asamblare. Mai mult, daca programul apeleaza functii ale sistemului de operare executia sa pe un calculator va fi conditionata nu numai de tipul procesorului ci si de prezenta sistemului de operare ale carui functii le apeleaza programul. Spunem in acest caz ca programul este dependent de platforma (procesor + sistem de operare). Pentru a nu rescrie programele pentru fiecare tip de calculator in parte si pentru a usura elaborarea, depanarea si modificarea lor s-au conceput asa numitele limbaje de nivel inalt. Acestea sunt limbaje artificiale, avand un vocabular si o sintaxa care permit descrierea unor operatii complexe. Primul limbaj de acest tip a fost FORTRAN (FORmula TRANslator). Acesta permitea in principal formularea unor instructiuni de calcul a expresiilor algebrice (formule) continand paranteze, variabile, constante, operatori, functii, intro forma apropiata de cea folosita in algebra. Datele puteau fi scalari – numere reale sau intregi - sau structuri similare vectorilor si matricilor. De asemenea limbajul prevedea instructiuni puternice de introducere si afisare a datelor de la si spre diferite echipamente periferice si pentru lucrul cu fisiere. Programele scrise intr-un limbaj de nivel inalt nu sunt dependente de platforma si din acest motiv pot fi usor insusite de nespecialisti in tehnica de calcul (ingineri, fizicieni, economisti, medici, etc.). Pentru a scrie un program intr-un limbaj de nivel inalt nu este necesar sa cunosti detalii despre calculatorul sau sistemul de operare sub care va fi executat acesta. Ca si programele in limbaj de asamblare, programele scrise in limbaj de nivel inalt nu pot fi “intelese” de calculator trebuind sa fie “traduse” in cod masina pentru a fi executate. Aceasta “traducere” se face prin substituirea fiecarei

PROGRAMARE IN JAVA - Note de curs

3

instructiuni cu codul masina a carui executie duce la realizarea prelucrarii descrise de instructiune. Spre deosebire de instructiunile in limbaj de asamblare instructiunile in limbaj de nivel definesc operatii de calcul complexe fiind substituite la traducere nu cu una ci cu mai multe instructiuni masina. Operatia aceasta de “traducere” a unui program scris in limbaj de nivel inalt in cod masina se numeste compilare si este realizata de programe specializate numite compilatoare. Codul masina generat de compilator se adreseaza evident unui anumit tip de procesor si unui anumit sistem de operare. Pentru a putea fi executat pe o alta platforma, programul sursa trebuie recompilat cu un alt compilator care genereaza cod masina pentru procesorul si sistemul de operare date. Cu alte cuvinte programul in cod masina obtinut prin compilare nu este independent de platforma. O alta varianta de executie a unui program scris in limbaj de nivel inalt consta in utilizarea unui program numit interpretor. Interpretorul preia succesiv cate o singura instructiune a programului sursa, o “interpreteaza” si o executa. Programele interpretate se executa mai lent decat programele compilate in cod masina. Pe de alta parte compilarea este un proces care dureaza si atunci in faza de elaborare a programului este preferabil sa folosim daca este posibil un interpretor si abia cand programul a fost definitivat sa il compilam. Primul limbaj interpretat a fost BASIC.

Limbajul C si C++
In anul 1970 la Bell Laboratories s-a inceput dezvoltarea unui nou sistem de operare pentru minicalculatoare, numit UNIX. O prima versiune a acestui sistem a fost scrisa pentru minicalculatorul DEC – PDP7 in limbajul B (creat de Martin Richards) orientat pentru programare de sistem. UNIX se dorea sa fie un sistem de operare portabil, scris in limbaj de nivel inalt, putand astfel sa fie compilat si instalat pe orice tip de minicalculator, cu conditia sa fie disponibil un compilator pentru limbajul de nivel inalt folosit. In 1972 pentru elaborarea unei noi versiuni UNIX, Dennis Ritchie pornind de la limbajul B il dezvolta creand limbajul C si compilatorul pentru DEC - PDP11. Odata cu raspandirea in mediul universitar a sistemului de operare UNIX si limbajul C devine din ce in ce mai cunoscut si folosit ca instrument de dezvoltare a UNIX. In prezent compilatorul limbajului C este disponibil pe toate tipurile de calculatoare ceea ce permite scrierea de aplicatii portabile mai ales dupa ce in 1983 limbajul a fost standardizat de American National Standards Committee on Computers and Information Processing. In 1989 standardul este aprobat de ANSI in cooperare cu ISO (International Standards Organization)(ANSI C). In 1980, tot la Bell Laboratories, Bjarne Stroustrup extinde limbajului C adaugandu-i facilitati necesare programarii orientate pe obiecte. Noua versiune a limbajului este numita C++. Conceptul de programare orientata pe obiecte revolutioneaza tehnologia de elaborare aprogramelor. Obiectele sunt componente software refolosibile, modeland obiectele din lumea reala. In aceasta abordare programele se construesc cu ajutorul acestor componente ca intr-un joc cu cuburi. Lucrul in echipa la proiectarea si dezvoltarea programelor folosind aceste componente modulare este mult mai productiva decat in cazul folosirii tehnologiilor utilizate anterior (modularitate, programare structurata). C++ permite scrierea programelor atat in stilul C clasic cat si in stilul orientat pe obiecte. Ulterior au aparut si alte limbaje de programare orientata pe obiecte cum ar fi Smaltalk elaborat de Xerox Palo Alto Research Center (PARC) si limbajul Java elaborat de Sun. Practic toate sistemele de operare aparute dupa 1972 au fost scrise in C/C++.

4

CURS 1

Limbajul Java
Numarul de calculatoare personale este de sute de milioane in toata lumea si numarul acesta este in crestere. Totodata interconectarea acestora intr-o retea globala (Internet) este tot mai accentuata. Descoperirea microprocesorului a revolutionat si productia de sisteme numerice de conducere cu utilizarea lor in numeroase aplicatii industriale, comerciale sau casnice. Utilizarea microprocesoarelor face posibila aparitia unor utilaje si aparate inteligente – casa inteligenta nu mai este o fantezie scifi. Ca si calculatoarele personale si aceste aparate inteligente pentru a functiona eficient vor trebui sa fie interconectate in retea. De exemplu nu este greu de imaginat un sistem inteligent care sa – mentina constanta umiditatea pamantului in ghivecele cu flori si sa schimbe apa si sa mentina temperatura la pestisori in timp ce noi suntem plecati in vacanta. Mai mult, prin Internet vom putea de la orice distanta sa intram in legatura cu sistemul si sa aducem corectii la valorile prescrise pentru umiditate si temperatura, sa vedem imaginea acvariului cu pestisori pe displayul PC-ului si chiar sa le vorbim. Intrucat diversele aparate inteligente care vor fi comercializate nu vor fi echipate cu acelasi tip de procesor apare problema elaborarii unor aplicatii independente de platforma. Prevazand aceste evolutii, firma Sun a lansat in anul 1991 un proiect de cercetare numit Green. Rezultatul a fost un limbaj de programare derivat din C si C++, botezat de autorul sau James Gosling Oak dupa numele varietatii unui arbore ce crestea in fata geamului biroului sau. S-a descoperit mai tarziu ca un limbaj de programare cu acest nume exista deja si atunci, dupa ce au fost la o cafeanea la o cafea, cercetatorii au ales pentru noul limbaj de programare numele Java. Deoarece piata aparatelor inteligente nu se dezvolta asa de repede si datorita pierderii unui contract pentru care Sun concurase, programul Green a inceput sa aibe dificultati de finantare fiind pe cale sa fie abandonat. Din fericire pentru proiect si Java, in anul 1993 a aparut si a capatat o evolutie exploziva in Internet serviciul WorldWideWeb (WWW). Cercetatorii Sun implicati in proiect au sesizat imediat potentialul oferit de utilizarea limbajului Java in crearea asa numitelor pagini Web cu continut dinamic. Noile perspective au revitalizat proiectul Green astfel ca in Mai 1995 firma Sun face cunoscute rezultatele cercetarilor la o conferinta SunWorld. Aparitia java este imediat sesizata si apreciata de cercurile de afaceri interesate de aspectele utilizarii comerciala a serviciului WorldWideWeb. In aceste conditii Java nu se prezinta ca un limbaj academic cum a fost Pascal si nici ca un limbaj destinat uzului individual sau al unui grup de programatori caum este C. Java este un limbaj promovat de interesul cercurilor de afaceri pentru utilizarea comerciala a Internet in conexiune cu WWW.

Tehnologii de programare
La inceputurile sale programarea se facea “dupa ureche” in functie de talentul, experienta si de capacitatea de analiza si sinteza a programatorului. La proiectarea programului se pornea de la reprezentare grafica (numita schema logica) a algoritmului de rezolvare a problemei. O astfel de schema logica este de fapt un graf orientat ale carui noduri sunt operatiile de prelucrare a datelor reprezentate prin simboluri grafice adecvate. Nodurile sunt conectate prin arce orientate care stabilesc succesiunea de efectuare a operatiilor. O astfel de abordare ofera prea multa libertate in proiectarea algoritmului. Nu intamplator, in acea vreme cea mai importanta instructiune discutata in manualele de programare era instructiunea de salt GOTO.

PROGRAMARE IN JAVA - Note de curs

5

Limbajul FORTRAN avea o multime de variante a acestei instructiuni. Datorita acestei lipse de restrictii in proiectarea fluxului de calcul adeseori codul sursa devenea foarte “incalcit” greu de inteles, de modificat si mai ales nesigur, in special in cazul programelor cu complexitate mare. Activitatea de cercetare a dus la aparitia in anii 60 a conceptelor programarii structurate care introducea o anumita disciplina in elaborarea programelor. Respectand principiile programarii structurate programele capata o structura precisa, sunt mai usor de inteles, de testat, depanat si de modificat. In aceasta abordare, la proiectarea programului nu mai este necesara elaborarea schemelor logice. Deoarece in acea perioada nu existau limbaje de programare care sa ofere suport pentru programarea structurata, Nicklaus Wirth a elaborat in 1971 limbajul de programare Pascal (dupa numele matematicianului Blaise Pascal – creator al primei masini mecanice de calcul) pentru a fi folosit la predarea programarii in mediile academice. Cu acest limbaj, Wirth a introdus si conceptul de structura de date –indisolubil legat de algoritmul ce sta la baza programului. Pascal a devenit in scurt timp limbajul preferat predat in universitati. Conceput in scopuri didactice limbajul avea o serie de slabiciuni care au facut sa nu fie agreeat pentru dezvoltarea aplicatiilor comerciale, industriale si guvernamentale. In anii 70-80 Departamentul Apararii al S.U.A. (DOD) a lansat o cerere pentru elaborarea unui limbaj de programare ce urma sa inlocuiasca sutele de limbaje de programare folosite la acea data in sistemele sale. Noul limbaj urma sa devina unicul limbaj de programare folosit in sistemele sale de calcul. Limbajul astfel obtinut s-a numit Ada (dupa numele primului programator al unei masini de calcul – construita de matematicianul Charls Babbage – Lady Ada Lovelace, fica poetului englez Lord Byron). Chiar daca este un urmas al Pascalului, limbajul Ada este mult diferit de acesta. El introduce printe altele mecanismul de multitasking care permite programatorului sa defineasca procesari ale datelor care decurg in paralel. C++ si Java prevad si ele acest mecanism sub denumirea de multithreading. Am vazut ca C++ si Java introduc in plus conceptul de programare orientata pe obiecte oferind si suportul necesar implementarii acestuia. Conceptul de obiect “incapsuleaza” la un loc datele si procedurile de prelucrare a acestora intr-o singura entitate, extinzand astfel conceptul de structura de date din Pascal.

Mediul de dezvoltare a aplicatiilor Java
Programele Java parcurg cinci faze de dezvoltare: editare, compilare, incarcare, verificare si executie. Schematic aceste etape pot fi reprezentate ca in figura 1.1. Prima faza consta in editarea programului folosind un editor de text (cum ar fi Notepad-ul din Windows sau vi –ul din UNIX). Programul sursa va fi salvat intr-un fisier cu extensia java (de exemplu prg1.java) In a doua faza programul java este compilat folosind comanda javac (de exemplu javac prg1.java) pentru a lansa compilatorul. acesta “traduce” programul sursa in cod binar (byte code) – limbaj inteles de interpretor. Acest cod intermediar este salvat intr-un fisier cu extensia class (de exemplu prg1.class). Faza a treia consta in amplasarea codul binar din fisierul class in memorie de catre incarcator. Incarcarea se poate face de pe discul local sau prin retea. Exista doua tipuri de programe java – aplicatii si applet-uri. in cazul aplicatiilor java aceasta operatie este initiata de comanda java (de exemplu java prg1). Appleturile sunt destinate executiei de catre o masina virtuala java implementata de un browser (de exemplu Internet Explorer sau Netscape Navigator) in cadrul unui document HTML (

6

CURS 1

Figura 1.1 – mediul de dezvoltare al programelor Java HyperText Markup Language). Un applet poate fi executat si local cu ajutorul programului appletviewer.

Clase si Obiecte Java

In Java un program este constituit dintr-o comunitate de obiecte care interactioneaza intre ele in timpul executiei programului. Fiecare obiect component al programului are propriile sale proprietati si un anumit comportament specific.

Putem reprezenta un obiect ca in Figura 1. fiind accesibile din afara obiectului.3. oricat de perfectionat.2 – prelucrarea procedurala a datelor In cazul programelor orientate pe obiecte lucrurile stau oarecum diferit. Un program de calculator este o masina de prelucrare a informatiei asemanator storcatorului de fructe dar cu deosebirea ca este mult mai versatil. O astfel de colectie de componente constitue un sistem motiv pentru care programele de calculator sunt numite uneori si sisteme informatice. problema este descompusa in subprobleme ce urmeaza a fi abordate separat. Un storcator de fructe. un program de calculator este facut din diferite repere (parti) componente care interactioneaza intr-un mod definit cu precizie. Si aceste programe sunt sisteme constituite din componente care interactioneaza intre ele dar aceste componente nu implementeaza algoritmi de rezolvare a unor subprobleme ca procedurile. Putem spune ca este similar unui storcator de fructe. Asa cum introducand portocale si energie electrica in storcator obtinem la iesire suc. un astfel de obiect are o serie de proprietati – de exemplu culoare. . Programul obtinut are drept componente aceste proceduri care la executie interactioneaza pentru obtinerea rezultatului. 2 si 3 asupra proprietatilor la solicitari venite din exterior de la alte obiecte. tot asa introducand in program datele initiale obtinem la iesire rezultatele. In cazul programelor complexe. coordonate. Asa cum in cazul unei masini comanda de accelerare ii modifica parametrii de stare viteza si coordonate tot asa actiunile obiectului ii modifica valorile proprietatilor. In mod traditional. ele sunt la randul lor descompuse in subprobleme mai simple. Detalierea continua pana cand fiecare subproblema poate fi rezolvata de un subprogram numit subrutina. dimensiune. O astfel de abordare de la complex la simplu prin detalieri succesive se numeste metodologie top-down de dezvoltare a programelor. procedura sau functie in functie de limbajul de programare folosit. nu stie sa faca decat un singur lucru.2 de la un punct de prelucrare la altul (de la o procedura la procedura) pana la procesarea completa. Figura 1. Un program de calculator poate sa fie proiectat astfel incat sa modeleze nu numai procese si sisteme existente in lumea reala dar si lucruri care nu au existat si nu ar putea exista in realitate. proiectantul se concentreaza in special pe ce prelucrari trebuie sa faca programul. la elaborarea unui astfel de sistem de procesare a informatiei. Totodata obiectul are un anumit comportament specific fiind capabil de a efectua in anumite conditii o serie de actiuni care ii modifica starea. Spunem ca aceste actiuni sunt publice. La fel ca si obiectele din lumea reala.Note de curs 7 Un program este un sistem de procesare a datelor. Daca unele din aceste subprobleme au inca un grad ridicat de complexitate. Aceste componente reunesc datele cu procedurile de prelucrare ale acestora intr-o singura entitate denumita obiect. La fel ca si majoritatea masinilor.PROGRAMARE IN JAVA . Obiectul executa actiunile 1. In cazul unui program procedural datele sunt prelucrate similar cu prelucrarea unor piese intr-o linie de productie fiind transmise ca in figura 1.

8

CURS 1

Figura 1.3 Reprezentarea unui obiect Actiunea 4 este “interna” obiectului si nu poate fi solicitata din exterior. Spunem despre ea ca este o actiune privata. Proprietatile obiectului sunt si ele private, valorile lor neputand fi modificat direct din exterior ci numai prin actiunile obiectului insusi. Proprietatile obiectului se numesc variabile reprezentand de fapt datele supuse prelucrarii. Actiunile de care obiectul este capabil si care definesc comportamentul sau sunt de fapt proceduri ce se executa la apel asupra datelor interne ale obiectului. Aceste proceduri se numesc metode. Variabilele si metodele se numesc membri ai obiectului. Mai multe obiecte pot “coopera” intre ele pentru rezolvarea unei probleme asa cum motorul coopereaza cu carburatorul, pompa de benzina si rezervorul de combustibil pentru a deplasa un autoturism. In alta ordine de idei obiecte simple pot fi “asamblate” impreuna pentru a crea un obiect mai complex la fel cum obiectul autoturism se obtine din asamblarea impreuna a caroseriei, motorului, carburatorului, pompelor de apa si benzina, rezervorului si a altor repere. Motorul este la randul sau constituit din mai multe repere mai simple. Un program java este el insusi un obiect complex care poate fi construit folosind o serie de obiecte de complexitate mai redusa compuse la randul lor din obiecte mai simple, care la randul lor … Toate aceste obiecte componente coopereaza la rezolvarea problemei. In aceasta abordare proiectarea unui program orientat pe obiecte difera fundamental de proiectarea unui program procedural. Se porneste de la realizarea sau refolosirea unor obiecte simple pentru a construi obiecte din ce in ce mai complexe, obiectul rezultat in final fiind capabil sa prelucreze datele de intrare in modul dorit. Astfel proiectarea unui program orientat pe obiecte se aseamana cu proiectarea hardware. Circuitele integrate sunt obiecte cu un anumit comportament care se asambleaza pe placi de textolit cu cablaj imprimat rezultand un modul care el insusi este un obiect cu comportamentul dorit. Mai multe astfel de module se pot

PROGRAMARE IN JAVA - Note de curs

9

asambla impreuna pe un sasiu (sertar cu sloturi) pentru a forma un obiect mai complex. Mai multe sertare pot fi asamblate impreuna intr-un dulap cablat corespunzator rezultand un obiect si mai complex. La randul sau mai multe dulapuri de acest tip pot fi asamblate impreuna intr-o camera de comanda si interconectate intre ele rezultand un sistem extrem de complex care in esenta este si el un obiect. O astfel de abordare de la simplu la complex se numeste metodologie down-top de proiectare software (total diferita de metodologia top-down folosita la proiectarea programelor procedurale). La creare obiectele sunt personalizate printr-un nume (identificator ) cu ajutorul caruia ne putem referi la obiectul respectiv. Pentru a crea un obiect trebuie sa definim care sunt proprietatile si comportamentul acestuia. Aceasta definire se numeste clasa. Obiectele sunt instantieri ale clasei date. Asa cum toate autoturismele pot fi incadrate intr-o clase de obiecte numita Autovehicule caracterizate prin proprietatile model, capacitate cilindrica, culoare, numar locuri etc. si capabile de actiunile acelerare, franare, schimbare a directiei, aprindere faruri, semnalizare, etc. si obiectele software se incadreaza intr-o clasa. Crearea obiectului se face pe baza definitiei clasei careia apartine obiectul prin alocarea unui bloc de memorie si completarea acestuia cu datele si codul corespunzatoare. Zona de date a blocului de memorie se initializeaza cu valorile specificate la crearea obiectului. Avantajele programarii orientata pe obiecte sunt multiple: - obiectele construite pot fi testate usor fiecare in parte astfel ca la folosirea lor la realizarea unor obiecte mai complexe putem fi siguri de buna lor functionare. Aceasta duce la o mai mare siguranta a programelor. - obiectele odata realizate, pot fi refolosite si in alte aplicatii. - munca in echipa este evident mai eficienta. - Programele orientate obiect sunt mai usor de modificat prin simpla inlocuire a unora din obiectele componente. Asa cum pe placa de baza a unui PC putem inlocui un procesor mai lent cu altul mai rapid fara a modifica celalalte componente, tot asa putem inlocui un obiect cu un altul avand acelasi comportament dar la realizarea caruia s-au folosit algoritmi mai performanti. Noul obiect fiind compatibil la nivel de “interfata” cu obiectul inlocuit, celalalte obiecte componente nu trebuiesc modificate. Programul insa va fi mai eficient beneficiind de performantele imbunatatite ale noului obiect introdus. - Programele orientate obiect complexe sunt mult mai usor de proiectat si de inteles.

Mostenirea

Unul din avantajele majore al POO il constituie mostenirea. Aceasta ii permite programatorului sa nu reinventeze roata de fiecare data de cate ori incepe sa lucreze la un nou program. De ce sa fii nevoit sa rezolvi probleme pe care le-ai rezolvat odata, anterior sau pe care alti programatori le-au rezolvat deja inaintea ta. In cazul programarii procedurale aceasta problema era solutionata prin existenta unor biblioteci de functii. Functiile si procedurile de biblioteca pot fi apelate din programul nou creat de noi, codul acestora fiind cautat si extras din fisierul de biblioteca corespunzator si adaugat programului in cod masina obtinut la compilare prin operatia de editare a legaturilor (linkeditare). Utilizarea bibliotecilor de functii are insa o mare limitare – ea nu ofera un mecanism de extindere a capabilitatilor functiilor continute, acestea fiind deja in cod masina si neputand fi modificate. POO ofera un mecanism

10

CURS 1

elegant si revolutionar, numit mostenire, de a depasi aceasta limitare. Locul bibliotecilor de functii este luat in cazul POO de bibliotecile de clase. Clasele pot fi extinse prin adaugare de noi proprietati si metode fara a modifica codul lor initial. Aceasta se bazeaza prin definirea unei clase derivate din clasa de baza continuta eventual de biblioteca. Noua clasa “mosteneste” proprietatile si metodele clasei de baza carora li se adauga proprietatile s metodele specificate la definirea clasei de baza. O astfel de clasa derivata din clasa de baza se numeste subclasa a acesteia. O parte din bibliotecile de clase java sunt standard acompaniand compilatorul si interpretorul Java, altele putand fi furnizate de alti producatori de software independenti. De asemenea, programatorul poate sa creeze propriile sale biblioteci clase pe care sa le foloseasca in diferite aplicatii.

Crearea unui program Java
Vom incepe prin a dezvolta o aplicatie Java extrem de simpla (traditionalul (HalloWorld) pentru a exemplifica structura unui astfel de program si etapele ce trebuiesc parcurse pentru a-l executa. Vom incepe prin a edita cu un program editor de text codul sursa al aplicatiei. Asa cum am am spus anterior, un program java este el insusi un obiect. Vom incepe prin a defini clasa a carei instantiere este aplicatia noastra: class HalloWorld { //Aici se vor adauga membrii clasei } Pentru ca aceasta clasa sa defineasca o aplicatie, ea trebuie obligatoriu sa contina metoda main care este apelata la lansarea in executie a programului. Metoda main este de fapt o functie (similara cu functiile C) care primeste ca parametri un vector de siruri de caractere reprezentand argumentele din linia de comanda cu care a fost lansat programul. In Java sirurile de caractere sunt (ca toate datele de altfel) obiecte apartinand clasei String. Un vector de astfel de obiecte este definit ca String[]. Aceasta functie trebuie sa fie accesibila din exteriorul obiectului pentru ca interpretorul sa poata cere executia acesteia, sa fie publica, motiv pentru care este declarata de tip public. Codul acestei functii este comun tuturor instantelor clasei metoda fiind declarata din acest motiv static. De asemenea main nu intoarce nimic fiind deci declarata void. Vom avea deci: class HalloWorld { public static void main(String[] arguments){ //Aici se va adauga codul functiei main } } In cazul exemplului nostru, dorim ca functia noastra sa afiseze mesajul Hallo world!. Pentru afisare vom solicita serviciile obiectului System care gestioneaza relatiile cu sistemul. Acesta are in componenta un obiect out care gestioneaza afisarea. Accesul la membrul out al lui System cu operatorul de acces “.” ( la fel cum se accesau membrii unei structuri in C): System.out . Acestei componente ii vom solicita sa afiseze mesajul nostru prin apelul metodei sale println. Vom obtine deci:

PROGRAMARE IN JAVA - Note de curs
class HalloWorld { public static void main(String[] arguments){ System.out.println(“Hallo world!”); } }

11

Se observa ca instructiunea adaugata de noi la corpul functiei trebuie terminata ca si in limbajul C cu caracterul ";". Textul programului il vom salva intr-un fisier avand acelasi nume cu classa si extensia java (HalloWorld.java). Vom compila programul cu comanda javac HelloWorld.java rezultand fisierul HelloWorld.class continand byte-codul programului. Acest byte-cod il vom executa cu interpretorul java prin comanda java HelloWorld. Programul va afisa in fereastra DOS in care a fost executat mesajul Hello world! si se va termina (figura 1.4).

Figura 1.4 – Compilarea si executia unui program java

Sumar
Pe parcursul acestui curs am discutat aspectele introductive legate de limbajul Java si POO. Am elaborat de asemenea un prim program java si am parcurs etapele necesare pentru executia acestuia: 1. Se editeaza programul cu un editor de text; 2. Se compileaza programul; 3. Se apeleaza interpretorul pentru executarea byte-codului generat de compilator. Parcurgand aceste etape am vazut cum se defineste o clasa si cum se declara in cadrul acesteia o metoda. De asemenea am vazut cum se apeleaza la serviciile unui alt obiect existent – in speta pentru afisarea unui mesaj am apelat metoda System.out.println(<mesaj>). Unde <mesaj> este un sir de caractere incadrat intre ghilimele. Aceasta metoda afiseaza sirul de caractere la consola sistemului (in fereastra DOS in care am rulat aplicatia) si trece cursorul pe randul urmator. Trebuiesc de asemenea remarcate urmatoarele detalii de sintaxa: • clasa se declara cu instructiunea class; • Programul Java este instantierea unei clase care contine metoda main; • Metoda main este de tip public static void si are ca parametru String[]; • Numele clasei trebuie sa fie acelasi cu numele fisierului in care se salveaza codul acesteia; • In textul programului pot fi introduse comentarii precedate de perechea de caractere “//” (la fel ca in C), compilatorul ignorand textul ce urmeaza acestor caractere pana la sfarsitul randului. • Instructiunile programului se termina cu caracterul “;”. Mai multe detalii privind cele de mai sus vor prezentate in cursurile urmatoare.

12

CURS 1

Exercitii
1. Cand compilati un program, ce faceti de fapt? a. Il salvati pe disc b. Il convertiti intr-o forma pe care calculatorul poate sa o inteleaga c. Il adaugati la colectia voastra de programe 2. Ce este o variabila? a. O valoare necunoscuta ce este precizata in timpul executiei programului b. Un text intr-un program ignorat de compilator c. Un loc unde vor fi pastrate de catre program informatii 3. Modificati programul HalloWorld introducand in codul sau diverse erori. De exemplu stergeti terminatorul “;” de la sfarsitul instructiunii de afisare sau modificati numele clasei din class HalloWorld{...} in class halloWorld{...}. Salvati programul si incercati sa il compilati si executati. Comparati mesajele de eroare obtinute cu erorile introduse.

PROGRAMARE IN JAVA - Note de curs

13

Curs 2
Algoritmi si structuri de control
Inainte de a incepe scrierea unui program care sa rezolve o anumita problema, programatorul trebuie sa analizeze si sa inteleaga pe deplin in ce consta problema care sunt datele initiale, care sunt rezultatele ce trebuiesc obtinute si ce prelucrari trebuie sa sufere datele initiale pentru a se obtine rezultatele cerute. La proiectarea programului este esential atat sa determinam ce blocuri componente vom folosi pentru a construi programul cat si ce metodologie de elaborare vom utiliza pentru aceste blocuri. Metodologia prezentata in continuare de proiectare a structurii programelor este aplicabila nu numai limbajului java ci si in cazul majoritatii limbajelor de programare de nivel inalt. orice problema de calcul poate fi rezolvata prin efectuarea unor anumite operatii asupra datelor intr-o succesiune data. O astfel de succesiune de efectuare a operatiilor asupra datelor initiale care duce la solutionarea unei probleme date ( prin obtinerea rezultatelor dorite) se numeste algoritm. Sa analizam pe un exemplu importanta succesiunii corecte a efectuarii a operatiilor in rezolvarea corecta a problemei. Fie algoritmul de desteptare si plecare la cursuri a unui student: 1. Trezirea si jos din pat 2. Dezbraca-ti pijamaua 3. Fa un dus 4. Imbraca-te 5. Ia micul dejun 6. Pleaca la cursuri Executarea in aceasta ordine a operatiilor descrise mai sus face ca studentul nostru sa ajunga la cursuri intr-o forma corespunzatoare. Acum sa presupunem ca studentul ar executa aceleasi operatii intr-o ordine putin modificata: 1. Trezirea si jos din pat 2. Dezbraca-ti pijamaua 3. Imbraca-te 4. Ia micul dejun 5. Fa un dus 6. Pleaca la cursuri Aplicand acest algoritm, studentul nostru va ajunge la cursuri ud fleasca. Specificarea ordinii in care se executa diferitele instructiuni ale programului se face prin instructiuni de control. Inainte de atrece la scrierea programului este necesar deci sa determinam operatiile ce trebuiesc efectuate de acesta si succesiunea acestora adica sa determinam algoritmul de rezolvare a problemei care urmeaza sa fie implementat in final in limbajul de programare ales. Inainte de a fi transpus in program, algoritmul trebuie reprezentat intr-o forma sau alta pe hartie. Folosirea limbajului natural nu este cea mai buna solutie pentru descrierea algoritmului. O solutie o constitue utilizarea pseudocodului – un limbaj artificial neformal apropiat de un limbaj de programare dar

14

CURS 2

mai putin rigid in ce priveste respectarea regulilor sintactice. Pseudocodul nu este un limbaj de programare propriuzis, servind numai pentru reprezentarea algoritmului ceea ce reprezinta o etapa intermediara in elaborarea programului. El permite programatorului sa analizeze si sa proiecteze structura si componentele viitorului program. Implementarea algoritmului reprezentat astfel in program se face foarte usor prin inlocuirea instructiunilor scrise in pseudocod cu instructiunile echivalente ale limbajului de programare ales. Pseudocodul contine doar instructiuni executabile. Instructiuni declarative de forma int i; nu apar in aceasta etapa de proiectare a programului. O astfel de instructiune declarativa este de fapt o directiva data compilatorului pentru a aloca memorie variabilei i in care sa se pastreze in timpul executiei valorile luate de aceasta. Deoarece programul in pseudocod nu va fi compilat, nu va fi necesara in aceasta faza de conceptie declararea variabilelor ce intervin in program. Cu toate acestea unii programatori prefera sa specifice la inceputul pseudocodului programului lista variabilelor folosite si destinatia acestora. In mod normal, instructiunile sunt executate succesiv, una dupa alta in ordinea in care apar in program. O astfel de executie se numeste secventiala. Multe instructiuni Java pe care le vom discuta curand permit programatorului sa determine executarea (sa transfere controlul) unei alte instructiuni decat instructiunea imediat urmatoare din secventa. Abuzul in ce folosirea acestor instructiuni poate sa altereze grav structura programului ridicand mari dificultati in intelegerea, depanarea si modificarea acestuia. Am vorbit in cursul precedent de blamata instructiune goto care permitand transferul controlului in orice punct al programului, utilizata fara discriminare poate complica inutil programul. Astfel in anii 60, dupa cum am mai aratat, s-a formulat conceptul programarii structurate care duce la eliminarea folosirii acestei instructiuni. Cercetarile lui Bohm si Jacopini au dovedit prin enuntarea si demonstrarea in 1966 a teoremei de structura. Aceasta teorema afirma ca orice algoritm poate fi construit fara utilizarea lui goto folosind numai trei structuri de control: secventa, selectia si repetitia. Renuntarea la instructiunea goto a fost o adevarata provocare adresata producatorilor de software, programatorii trebuind sa–si modifice fundamental modul de gandire si stilul de programare. Analizele facute au demonstrat ca aplicarea principiilor programarii structurate au dus la o crestere impresionanta a eficientei productiei de software ( reducerea timpului de elaborare a software-ului si implicit a cheltuielilor). Explicatia acestui fenomen consta in imbunatatirea substantiala a structurii programelor ceea ce facea ca acestea sa fie mai clare, mai usor de depanat, testat si modificat. Desi limbajele C, C++ si Pascal mai pastreaza instructiunea goto, limbajul Java nu o mai contine in setul sau de instructiuni.

Secventa
Structura secventa este implicita in Java. Daca nu se specifica altfel, instructiunile sunt executate secvential, una dupa alta in ordinea in care apar in program. Fragmentul de schema logica din figura 2.1 exemplifica o astfel de structura de control de tip secventa tipica, in care doua operatii de calcul sunt executate succesiv. O schema logica este o reprezentare grafica a unui algoritm folosind diferite simboluri grafice pentru reprezentarea operatiilor (dreptunghiuri, romburi, cercuri, elipse). In schema logica din figura 2.1 dreptunghiurile reprezinta blocuri de calcul ( specificand o actiune/operatie executata de program) iar cercurile noduri de conectare la restul schemei logice. Sagetile indica ordinea in care operatiile sunt efectuate.

PROGRAMARE IN JAVA - Note de curs

15

Figura 2.1 – secventa Intai valoarea variabilei unghi este adaugata la variabila total iar apoi variabila contor este incrementata cu 1. Java ne permite sa prevedem oricate instructiuni succesive intr-o secventa.

Selectia
Selectia este o instructiune care introduce o ramificatie in fluxul de executie al instructiunilor programului. Executia instructiunilor se va desfasura pe o ramura sau alta in functie de indeplinirea unei conditii specificate. Java prevede trei tipuri de instructiuni de tip selectie: structura de selectie if , selectia dubla if/else si selectia multipla switch. Selectia simpla if determina executia unei operatii daca este este adevarata o conditie data. In cazul in care conditia nu este indeplinita (este falsa) se sare peste operatia conditionata trecandu-se la executia operatiei imediat urmatoare. O astfel de structura se numeste selectie simpla si poate fi reprezentata grafic prin schema logica din figura 2.2. Aici simbolul romb este un bloc de decizie. Daca valoarea de adevar a expresiei relationala inscrisa in acest bloc este adevarat ( variabila unghi are valoarea mai mare sau egala cu 60), se executa actiunea din blocul urmator (afisarea mesajului “Mai mare”). Daca valoarea de adevar este fals, atunci se sare peste aces bloc. de remarcat ca si aceasta structura de control if ca si secventa are un singur punct de intrare si un singur punct de iesire. Astfel de structuri cu un singur punct de intrare si un singur punct de iesire prezinta avantajul ca programatorul le poate conecta unul la altul folosindu-le ca elemente de constructie a programului la fel ca intr-un joc de cuburi. Aceasta confera algoritmului o structura clara, usor de inteles si modificat.

Structura descrisa mai sus poate transpusa in java astfel: . Ca argument al instructiunii de selectie if poate fi prevazuta orice expresie care returneaza la evaluare o valoare de tip boolean.println(“Mai mare”)... if(unghi >= 60) System. Aceasta structura se scrie in pseudocod astfel .. if(unghi >= 60) print “Mai mare” else print “Mai mic” ....out.2 – selectia simpla Mai exista o singura metoda de combibnare a structurilor de control de acest tip si anume incuibarea..3. . Schema logica corespunzatoare acestei structuri este prezentata in figura 2. Se observa ca limbajul java corespunde foarte bine pseudocodului folosit in descrierea algoritmului ceea ce face ca utilizarea pseudocodului la proiectarea algoritmilor sa fie un instrument extrem de util. Selectia dubla Structura de selectie dubla if/else permite programatorului sa specifice o actiune alternativa care se executa in cazul conditia nu este indeplinita. .16 CURS 2 Figura 2..

println(“Drept”)..out. .. va avea acelasi efect cu instructiunea if/else din exemplul anterior. if(unghi >= 60) System.println(“Mai mare”).println(“Ascutit”). else if (unghi == 90) System.3 – selectia dubla Structura descrisa mai sus poate transpusa in java astfel: . Astfel instructiunea java: . if(unghi < 90) System.out... .out. avand sintaxa: <expresie booleana>?<expresie1>:<expresie2> Daca la evaluarea expresiei booleene rezulta valoarea adevarat.. .. else System.Note de curs 17 Figura 2...PROGRAMARE IN JAVA .out.println(“Mai mic”). else System.println(“Obtuz”).out. System. .out. Pe langa instructiunea if/else limbajul java mai prevede operatorul conditional ?: similar celui din limbajul C...Putem incuiba structurile de selectie duble ca in exemplul urmator: ... operatorul evalueaza si intoarce valoarea expresiei 1 iar in caz contrar valoarea expresiei 2.println(unghi>=60? “Mai mare”:”Mai mic”).

else System.4 – Incuibarea selectiilor duble Este important de subliniat ca componenta else a structurii este intotdeauna asociata de compilator cu ultimul if.5. indiferent de indentarea textului. if(x > 10) if(y > 10) System.out.. .18 CURS 2 Schema logica corespunzatoare acestei secvente de instructiuni este cea din figura 2. va functiona incorect afisand mesajul x este mai mic sau egal cu 10 chiar daca x are valoarea 12 dar y este 5. Versiunea corecta se obtine folosind acoladele: ... Indentarea are doar rolul de a imbunatati claritatea programului. secventa corespunzand schemei logice din figura 2.out.4 Figura 2. Secventa de mai jos: . Daca dorim sa asociem o componenta else cu un alt if decat cel precedent trebuie sa folosim acoladele ca in exemplul urmator. Aceasta se datoreste faptului ca else este asociat cu if( y > 10) si nu cu if(x > 10).println(“x si y sunt mai mari ca 10”).println(“x este mai mic sau egal cu 10”)..

.out.println(“x si y sunt mai mari ca 10”). else if (unghi == 45) System.. else if (unghi == 90) System.println(“x este mai mic sau egal cu 10”). In acest exemplu daca variabila unghi are valoarea mai mica decat 60 este executat blocul de doua instructiuni incadrate de acolade. } . Instructiuni compuse In mod normal instructiunea if accepta in corpul sau o singura instructiune.out. Pentru astfel de cazuri in care. System. }else System.println(“Unghi=30”).out. Un astfel de bloc de instructiuni se numeste instructiune compusa. if(unghi >= 60) System. Acoladele {} indica compilatorului ca cel de al doilea if este incuibat in corpul primului si deci componenta else apartine primului if.PROGRAMARE IN JAVA . acestea pentru a fi incluse in corpul lui if trebuiesc grupate intr-un bloc de instructiuni prin incadrarea intre acolade. Daca nu s-ar fi folosit acoladele mesajul Mai mariti unghiul! ar fi fost afisat in oricare din situatii.println(“Unghi=60”).println(“Mai mic”)... trebuie selectata si executata o anumita actiune din mai multe posibile (selectie multipla) limbajul java prevede instructiunea switch avand sintaxa: . else{ System.out.println(“Unghi=45”)..println(“Alte valori”). Selectia multipla Fie urmatoarea instructiune formata din mai multe instructiuni de selectie incuibate: . if(unghi == 30) System.out.out. if(x > 10){ if(y > 10) System. Daca prelucrarea ce trebuie executata este mai complexa si necesita mai multe instructiuni. in functie de valoarea intreaga pe care o ia o variabila. afisandu-se pe doua randuri mesajele Mai mic si Mai mariti unghiul! . else System.out.. .out.println(“Mai mariti unghiul!”)... else if (unghi == 60) System.out.. ..println(“Unghi=90”). Exemplul urmator prezinta utilizarea instruciunilor compuse in corpul unei selectii duble: ..println(“Mai mare”).Note de curs 19 ..out.

out..println(“Unghi=30”). Folosind aceasta instructiune. <val2>. break.out.. Daca aceasta conditie este satisfacuta se executa o noua cumparatura. daca este <val 2> se va efectua <actiune 2>.. break. instructiunea compusa din exemplul precedent poate fi inlocuita cu: . caz in care evaluarea conditiei intoarce un rezultat fals. case 90: System. O astfel de structura repetitiva se numeste ciclu cu testul la inceput.. switch(unghi){ case 30: System. Un exemplu de astfel de operatie repetata ar fi descris de : Cat timp mai sunt obiecte de cumparat pe lista mea de cumparaturi Cumpara urmatorul obiect din lista Instructiunea while corespunde lui “Cat timp”. case 60: System. break.println(“Unghi=60”). case <val 2>: <actiune 2>...println(“Alte valori”). default: System. Structura de control repetitiva while O structura de control repetitiva determina calculatorul sa repete ciclic o actiune atat timp cat o anumita conditie este indeplinita (este adevarata). } .out. case 45: System. ..out.. default:<actiune implicita>.println(“Unghi=45”). break.20 CURS 2 switch ( <expresie intreaga> ){ case <val 1>: <actiune 1>. Repetarea continua pana la epuizarea listei de cumparaturi.. break.Daca valoarea obtinuta nu este egala cu nici una din valorile <val1>. break.out. etc. Actiunea constituie corpul ciclului iar conditia se numeste invariantul ciclului (denumire justificata de faptul ca acest ciclu se executa atat timp . Actiunea este descrisa de directiva “Cumpara urmatorul obiect din lista”. } Aici daca valoarea intreaga obtinuta prin evaluarea <expresie intreaga> este <val 1> se va efectua <actiune 1>. case <val n>: <actiune n>. Conditia verificata de fiecare data inaintea efectuarii acestei actiuni este “mai sunt obiecte de cumparat pe lista mea de cumparaturi?”..<val n> se va efectua <actiune implicita> specificata cu eticheta default. break.println(“Unghi=90”). break. break.

.5 Structura repetitiva while . Daca insa valoarea initiala este egala sau mai mare ca 360.. actiunea de incrementare a sa cu 10 nu are loc. Ciclul se numeste ciclu cu testul la inceput deoarece evaluarea conditiei se face inainte de a se executa actiunea din corpul ciclului.Note de curs 21 valoarea rezultata din evaluarea conditiei este invariant adevarat). Astfel este posibil ca aceasta actiune sa nu se execute nici o data (daca conditia are din start valoarea fals). Figura 2. Daca valoarea initiala a acestei variabile a fost 5. Instructiunea <instructiune> poate fi simpla sau compusa (bloc de instructiuni).5 reprezinta structura repetitiva while din exemplul de mai sus. while(unghi < 360) unghi = unghi + 10. valoarea la iesirea din ciclu va fi 365. In acest exemplu variabila unghi este marita ciclic cu 10 pana cand valoarea acesteia depaseste 360. Daca valoarea initiala este un multiplu de zece dar mai mica de 360.. Schema logica din figura 2.PROGRAMARE IN JAVA . valoarea finala obtinuta este 360. ciclul terminandu-se fara a se mai executa corpul sau deoarece conditia unghi < 360 este evaluata la valoarea fals de la inceput.. Exemplul urmator prezinta utilizarea instructiunii while: . Sintaxa instructiunii while este: while (<expresie booleana>) <instructiune> Instructiunea <instructiune> se repeta cat timp valoarea booleana obtinuta din evaluarea expresiei <expresie booleana> este adevarat. .

22 CURS 2 Structura de control repetitiva while Figura 2.6 – structura repetitiva do/while Sumar Exercitii .

numite tipuri de date scalare. cu caractere sau cu siruri de caractere. numite booleene dupa matematicianul englez Bool. evident ca de acelasi tip. De exemplu . Similar operatiilor din algebra. semne speciale. Java) prevad un tip de date specific. Caracterele. Exista de asemenea operatori relationali care permit compararea a doua date. Astfel avem operatori ce implementeaza operatiile cu numere intregi. Pe langa tipurile de date scalare toate limbajele de nivel inalt permit definirea unor structuri omogene de date cum ar fi vectorii si matricile. asa cum am constatat in cursul trecut. La executia programului expresia este evaluata prin aplicarea operatorilor asupra termenilor dupa niste reguli precise. programele trebuiesc adesea sa opereze cu valori logice de tip adevarat si fals. variabile. unele limbaje (Pascal. Si pentru acest gen de informatie limbajele de programare de nivel inalt prevad tipuri de date corespunzatoare. alti operatori pentru operatii cu date de tip real. Asa cum in algebra pe fiecare multime de numere exista definit un set de operatii si limbajele de nivel inalt prevad pentru fiecare tip de date un set de operatori. Fiecare limbaj de nivel inalt pune la dispozitia programatorului o colectie mai mult sau mai putin bogata de tipuri de date uzuale prin care acesta sa poata reprezenta in program informatia supusa procesarii.PROGRAMARE IN JAVA . Limbajele de nivel inalt moderne permit programatorului sa defineasca propriile tipuri de date sub forma de structuri eterogene (compuse din elemente de tipuri diferite) prin care acesta sa poata reprezenta si alte informatii decat cele uzuale. sunt codificate numeric prin asocierea fiecarui astfel de simbol a unui cod numeric standardizat (de exemplu codul ASCII – American Standard Code for Information Interchange). Totusi. De asemenea calculatoarele sunt frecvent folosite pentru prelucrarea informatiei de tip text numita informatie alfanumerica – caractere.Note de curs 25 Curs 3 Date. In aceasta categorie ar putea intra si sirurile de caractere – privite ca un vector ale carui elemente sunt date de tip caracter. motiv pentru care si pentru astfel de valori. sunt simboluri grafice cum ar fi litere. Tipurile de date discutate sunt tipuri elementare. operatorii pot fi unari actionand asupra unui singur operand sau binari avand doi operanzi. Din acest motiv din nici un limbaj de programare nu lipsesc aceste tipuri de date. Termenii expresiei sunt date de acelasi tip sau de tipuri compatibile. Java) trateaza sirurile de caractere ca un tip distinct de date. programele sunt sisteme care prelucreaza date. la nivelul programului scris in limbaj de nivel inalt ele modeleaza obiecte ale lumii reale. unele limbaje de programare (Pascal. cifre. Limbajele de nivel inalt permit construirea cu ajutorul operatorilor a unor expresii asemanatoare expresiilor algebrice. Desi in esenta aceste date sunt valori numere stocate in memoria calculatorului sub forma de numere intregi codificate in binar. expresii Asa cum am aratat. formate din mai multe elemente de acelsi tip. De asemenea. operatori ce opereaza cu date de tip boolean. In mod traditional calculatoarele sunt destinate sa prelucreze informatie numerica efectuand calcule cu numere intregi si reale.

De exemplu instructiunea: int scorMaxim. Denumirea tipulu float provine de la termenul englezesc Floating point – virgula mobila – care desemneaza modalitatea de codificare a numerelor reale in memoria calculatorului. Deoarece in memorie nu pot fi memorate decat numere . el este inlocuit cu data memorata in variabila. declara o variabila cu numele scorMaxim de tipul int. valoarea rezultata din evaluarea expresiei <expresie> este stocata in locatia de memorie desemnata de <variabila>. o astfel de expresie. Instructiunea: float punctajMediu. scaderi). Ordinea de efectuare a operatiilor poate fi controlata de programator prin folosirea parantezelor “( )”.14 miliarde. incadrata de paranteze rotunde poate sa fie termen intr-o alta expresie. De remarcat este faptul ca prin <expresie> se intelege chiar si o expresie cu un singur termen si fara nici un operator. o variabila trebuie sa fie declarata. impartiri) si apoi cele aditive (adunari. In programare variabila este caracterizata prin nume si tip. o expresie poate sa contina ca termeni si variabile. Deoarece inca nu i s-a atribuit acestei variabile o valoare. Compilatorul va aloca pentru aceasta variabila o locatie de memorie dimensionata sa poata stoca numere intregi cu valori cuprinse intre -2. Numele permite accesul la datele memorate in acea variabila. exista o diferenta intre instructiunea de atribuire si operatia de atribuire. la evaluarea acesteia. Daca numele unei variabile apare ca termen intr-o exprsie. Pentru a memora o data intr-o variabila (operatie numita de atribuire) unele limbajele de programare de nivel inalt prevad operatorul de atribuire iar altele instructiunea de atribuire cu sintaxa: <variabila> <op.atr><expresie> Desi sintaxa este identica. In primul caz. In cel de al doilea caz <variabila> <op. In programare variabila este o locatie de memorie destinata stocarii pe parcursul executiei programului a unui anumit tip de date.26 CURS 3 expresiile aritmetice se evalueaza ca si in matematica prin efectuarea calculelor de la stanga la dreapta. continutul acestei locatii de memorie este neinitializat. continand o valoare arbitrara. efectuandu-se intai operatiile multiplicative (inmultiri. Denumirea tipulu int provine de la cuvintul englezesc Integer – intreg. Declaratia trebuie sa specifice numele si tipul variabilei pentru ca la compilare sa i se aloce un spatiu de memorie suficient pentru a putea stoca date de tipul declarat. Tipul variabilei este acelasi cu tipul datelor pe care este prevazut sa le stocheze aceasta.atr><expresie> este ea insasi o expresie a carei valoare este chiar valoarea ce a fost memorata in variabila. Putem chiar la declarare sa atribuim variabilei o valoare intreaga prin operatorul de atribuire “=”: int scorMaxim = 40000. Numere intregi si reale Inainte de a fi folosita intr-un program java. declara o variabila cu numele punctajMediu de tipul float. Ca si in algebra.14 miliarde si +2.

Numele variabilelor este un identificator. continand o valoare arbitrara. continutul acestei locatii de memorie este neinitializat. numerele reale sunt memorate ca o pereche de numere intregi. fiecarui simbol grafic i se asociaza un cod numeric unic – un numar intreg cuprins intre 0 si 255.Note de curs 27 intregi. nici cifra (-). Caractere si siruri de caractere Asa cum am aratat mai inainte.372. Un identificator poate fi orice combinatie de litere sau cifre cu conditia sa inceapa cu o litera.456. Caracterul “_” este asimilat literelor.036. compilatorul va aloca o locatie de memorie de un octet in timp ce pentru una de tip int memoria alocata este de 4 octeti.372. Alte tipuri numerice de variabile Pe langa tipul int limbajul Java mai prevede tipuri derivate pentru variabile care stocheaza date de tip intreg. caracterele desemneaza simboluri grafice cum ar fi litere. Pentru cazul in care se doreste memorarea numerelor reale cu o precizie mai mare (cu mai multe zecimale) spatiul de memorie alocat trebuie dimensionat corespunzator.3). unul dintre acestea fiind codul ASCII.456 poate fi prezentat simplificat astfel: numarul este transformat prin deplasarea virgulei in numarul real echivalent 0. De exemplu modul de codificare in memorie a numarului real 123.123456 103 si memorat sub forma perechii de numere intregi (123456. Pentru codificarea in memorie a datelor de tip caracter.036. alte semne speciale care pot sa apara intr-un text.808 si 9.854.PROGRAMARE IN JAVA .775. cifre. De exemplu combinatiile Variabila1 sau Variabila_1 sau _X reprezinta identificatori valizi iar combinatiile 1X sau Variabila-1 nu sunt acceptati de compilator fie pentru ca incep cu o cifra ca in primul caz. In tabelul de mai jos sunt extrase codurile numerice asociate literelor si cifrelor: Caracter A-Z a-z 0-9 Cod ASCII 65-90 97-122 48-57 . semne de punctuatie. Deoarece inca nu i s-a atribuit acestei variabile o valoare.807. Tipul short determina dimensionarea locatiei de memorie la doi octeti pentru a pastra date cuprinse intre –32768 si 32767 iar tipul long 8 octeti pentrru a stoca numere intregi foarte mari cuprinse intre –9. ca in cel de al doilea caz.223. Pentru o variabila de tip byte. Exista mai multe standarde pentru codificarea caracterelor.775. Ca si in cazul variabilelor intregi putem atribui la declararea variabilei de tip float o valoare reala: float punctajMediu = 123. Compilatorul va aloca pentru aceasta variabila o locatie de memorie suficient de incapatoare incat sa permita memorarea unor numere reale reprezentate in virgula mobila. Tipul byte determina dimensionarea locatiei de memorie pentru a pastra date cuprinse intre –128 si 127.854.223. Pentru astfel de cazuri in locul tipului float se poate folosi tipul double (de la englezescul double precision – precizie dubla). fie datorita unui caracter care nu este nici litera.

28 CURS 3 Datele de tip caracter se reprezinta incadrate de apostroafe. Variabilele de tipul sir de caractere (String) se declara si se initializeaza ca in instructiunea de mai jos: String mesaj = “Hallo world!”.println(“Aceasta melodie este interpretata de \n formatia RoMania”) Va afisa pe display doua randuri de text: Aceasta melodie este interpretata de formatia RoMania Tipul de date boolean Java prevede si tipul boolean de date care pot avea doar doua valori.out. pot fi declarate variabile de tipul boolean ca in exemplul de mai jos: . De exemplu ‘C’ reprezinta caracterul C cu codul ASCII 67. Acelasi lucru este valabil si pentru caracterul apostrof care se va specifica cu secventa escape \’ ca si pentru caracterul backslash \ folosind \\ . Pentru a memora astfel de date. ca de exemplu sirul “Hallo world!” afisat de primul nostru program java. Daca vrem ca String-ul sa contina ghilimele ca in sirul de mai jos: Sunt student la Universitatea “Politehnica” din Bucuresti trebuie sa folosesc in locul ghilimelelor o secventa speciala de caractere \” . Sirurile de caractere se reprezinta incadrate cu ghilimele. adevarat – true si fals .false. numita secventa escape: String mesaj = “Sunt student la Universitatea \“Politehnica\” din Bucuresti”. O variabila de tip caracter (char) se declara si se initializeaza cu o instructiune de forma. char key = ‘C’. Secventele escape se folosesc si pentru introducerea in sir a unor caractere speciale de control al afisarii specificate in tabelul de mai jos: secventa escape \t \b \r \f \n Caracter de control tab backspace carriage return formfeed new line De exemplu folosind secventa escape \n instructiunea: System.

println(“Motanul Pacepa cintareste acum “ + greutate). System. initializandu-le si afisandule valorile.1.out.println(punctajMediu). Aplicatia noastra va consta in definirea clasei Variabile: class Variabile{ public static void main(String[] arguments){ // Declararea si initializarea variabilelor int scorMaxim=40000.PROGRAMARE IN JAVA . System. Spunem ca aceste variabile sunt locale metodei main.out. } } Variabilele de tipurile discutate au fost declarate in cadrul metodei main care realizeaza si procesarea acestora.println(“Motanul Pacepa viziteaza ulcica cu smintana“). String mesaj = “Hallo world!”.println(key).out.1 – Compilarea si executia aplicatiei Variabile. System. System. System. System.java Exemplu de utilizare a expresiilor Scopul aplicatiei prezentate in continuare este de a face o introducere in modul de utilizare a expresiilor in cadrul unui program Java.println(sfirsitJoc).out. Figura 3.out.456.println(mesaj).out.Note de curs boolean sfirsitJoc = false. System.out. // Afisarea valorii variabilelor System. . 29 Exemplu de declarare a variabilelor in program Vom aplica cele discutate mai sus intr-un program concret declarand diverse tipuri de variabile.java. double punctajMediu = 123. greutate = greutate + 1. boolean sfirsitJoc = false. char key = ‘C’.java precum si rezultatele afisate sunt redate in figura 3. System.println(“Motanul Pacepa cintareste “ + greutate). class MotanulPacepa{ public static void main(String[] arguments){ int greutate = 3. Programul de mai sus va fi editat si salvat in fisierul Variabile.println(“Motanul Pacepa descopera gimnastica aerobica“). Comenzile de compilare si executie a programului continut de fisierul Variabile.out.out.println(scorMaxim).

implicit. De asemenea in cadrul programului apar frecvent ca argument al metodei System. Figura 3. Data de tip String rezultata este tramnsmisa ca argument metodei System. Prezinta interes si expresiile de forma String + int in care cei doi operanzi sunt de tipuri diferite. System.out.pentru scadere. De fapt o astfel de explicitare nu era necesara deoarece.out.println.println(“Motanul Pacepa cintareste acum “ + greutate). System.out. System. Acestia au fost reprezentati prin simbolurile + pentru adunare. Comenzile de compilare si executie a programului continut de fisierul Variabile. avand ca rezultat un String format din inlantuirea celor doi operanzi de tip String. System.println expresii cu rezultat de tip String cum ar fi de exemplu: “Motanul Pacepa cade in masina automata de ” + “spalat rufe“. in baza unor reguli precise de conversie automata si de compatibilitate a tipurilor de date pe care le vom discuta in detaliu la momentul . greutate = greutate/2. In una din expresii au fost folosite parantezele pentru a explicita ordinea de efectuare a operatiilor – ca si in algebra.java precum si rezultatele afisate sunt redate in figura 3.println(“Motanul Pacepa este clonat de 12 ori“). In acest caz.out. la calculul expresiilor intai se executa operatiile din paranteze. In cadrul acestor expresii au fost folositi operatori aritmetici binari care se aplica la operanzi de tip intreg.out.println(“Motanul Pacepa cade in masina automata de ” + “spalat rufe“).2 Compilarea si executia aplicatiei MotanulPacepa. Aici simbolul + desemneaza operatia de concatenare a sirurilor de caractere. greutate = greutate + (greutate*12).println(“Cei 13 motani Pacepa cintaresc acum “ + greutate). . * pentru si / pentru impartire. } } Programul de mai sus va fi editat si salvat in fisierul MotanulPacepa.2.java In programul de mai sus am utilizat cateva expresii numerice cu rezultat intreg pentru a calcula valori noi pentru variabila greutate atribuite acesteia prin operatorul de atribuire reprezentat cu semnul =.30 CURS 3 greutate = greutate . asa cum am mai spus.println(“Motanul Pacepa cintareste acum “ + greutate).out. la calculul expresiilor intai se efectueaza operatiile multiplicative si apoi cele aditive.out. System.java.2.

Note de curs 31 potrivit. 3. ¾ operatorii unari de incrementare reprezentati prin ++ si decrementare reprezentati prin -. Daca operatorul de incrementare/decrementare se afla inaintea operandului (il prefixeaza) operandul este incrementat/decrementat iar noua valoare este folosita la evaluarea expresiei. In acest caz la evaluarea expresiei se foloseste valoarea continuta de operand.au ca efect incrementarea respectiv decrementarea operandului cu 1. iar x va contine valoarea 2 dupa aplicarea operatorului de predecrementare. ..println(“Motanul Pacepa cintareste “ + greutate). termenul de tip int este convertit la tipul String dupa care se aplica operatorul de concatenare. System. Abia dupa ce expresia a fost evaluata se incrementeaza x. Expresia --x are valoarea 2. Acest operator binar calculeaza restul impartirii intregi a primului operand la cel de al doilea operand. /). Cei doi termeni de tip String. Operatori pentru date de tip intreg In exemplul precedent am vazut o serie de operatori care actioneaza asupra datelor de tip intreg (+. aceasta valoare intreaga este convertita automat la valoarea de tipul String “3”. Expresia –x este echivalenta cu expresia x = x – 1. dupa evaluarea expresiei x—valoarea rezultata este 3 iar variabila x va contine valoarea 2.. Astfel expresia 14 % 3 are ca rezultat valoarea 2 (restul impartirii lui 14 la 3). int greutate = 3. Deoarece celalalt termen al expresiei este de tip String. Pe langa acestia. 2. Astfel daca variabila x contine valoarea 3. *. continutul lui x dupa aplicarea operatorului ++ este 4 iar valoarea rezultata din evaluarea expresiei x++ este 3 deoarece la evaluarea ei s-a folosit valoarea continuta de x. expresia “Motanul Pacepa cintareste “ + greutate este evaluata astfel: 1. . termenul greutate care este o variabila de tip int este inlocuit cu valoarea continuta adica 3.out. In acest caz operatia se numeste postincrementare/postdecrementare. aceasta expresie fiind echivalenta cu expresia x = x + 1. In acest caz operatia efectuata asupra operandului se numeste preincrementare/predecrementare. Astfel daca variabila x contine valoarea 3. Cu totul altfel stau lucrurile in cazul in care operatorul de incrementare/decrementare se afla amplasat dupa operand (il postfixeaza). Similar stau lucrurile si in cazul predecrementarii lui x. Similar. -. Actiunea acestor operatori depinde de locul pe care il ocupa in raport cu operandul. “Motanul Pacepa cintareste “ si “3” sunt concatenati rezultand sirul “Motanul Pacepa cintareste 3” care este transmis pentru afisare metodei println a obiectului System.PROGRAMARE IN JAVA . Acesti operatori accepta ca operanzi numai variabile de tip intreg... Abia dupa ce expresia a fost evaluata continutul variabilei careia i s-a aplicat operatia de postincrementare/postdecrementare este marit/micsorat cu 1. limbajul Java ofera programatorului urmatorii operatori: ¾ operatorul modulo reprezentat in expresii prin simbolul %.out. Astfel in secventa: . continutul lui x dupa aplicarea operatorului ++ este 4 iar valoarea rezultata din evaluarea expresiei ++x este 4.

-=. Daca se codifica o expresie algebrica in program trebuie avuta in atentie ordinea de efectuarea operatiilor.32 ¾ CURS 3 Foarte des in programe apar atribuiri de forma: <variabila x> = <variabila x><op><expresie> unde <op> este unul din operatorii +. -. La evaluare se va imparti variabila x la variabila y iar rezultatul obtinut se va inmulti cu variabila z.3. Astfel de exemplu ordinea efectuarii operatiilor la evaluarea expresiei 6*2/4+5*3 este prezentata in figura 3. Trebuie avute in vedere urmatoarele aspecte: 1. *. / sau % . Aceasta ar corespunde de fapt expresiei algebrice: x y ⋅ z O varianta de codificarea corecta in program este expresia: . Astfel de exemplu pentru a codifica expresia: x y ⋅ z vom fi tentati sa scriem: x/y*z Figura 3. /. *=. intai efectuandu-se operatiile multiplicative (*.-).3 – Ordinea de efectuare a operatiilor si precedenta operatorilor ceea ce este incorect. Astfel in loc de x= x+2 vom putea scrie x+=2 iar inloc de greutate = greutate + (greutate*12) putem scrie greutate+= (greutate*12).%) iar apoi cele aditive (+. cum ar fi de exemplu x= x + 2 sau greutate = greutate + (greutate*12). /= si %=. Precedenta Operatorilor Asa cum am mai spus expresiile numerice se evalueaza de la stanga spre dreapta. Limbajul Java ofera posibilitatea de a scrie simplificat astfel de expresii folosind operatorii += .

impartirea 2/3 ne da rezultatul 0 care inmultit cu 12 ne va da tot 0 in loc de rezultatul corect 8. va avea si valoarea rezultata din evaluare tot o valoare intreaga.Note de curs x/y/z 33 impartind pe x la y si rezultatul astfel obtinut la z. Astfel daca variabila contor a depasit numarul cunoscut de seturi de date ce trebuiau procesate ciclul se termina. care odata atinsa determina terminarea ciclarii (conditia de iesire din ciclu) . de la stanga spre dreapta. Solutia consta in utilizarea unei variabile care sa contorizeze seturile de date procesate deja. Avand deci in vedere ca expresia n/m (unde n si m sunt date de tip intreg ) are valoarea 0 daca n<m sa codificam acum expresia a carei valoare este evident 8: 2 ⋅ 12 3 Daca aceasta expresie o codificam in program: 2 / 3 * 12 desi totul pare corect. Putem evita astfel de situatii reordonand termenii expresiei: 2 * 12 / 3 Acum la evaluare se va calcula intai produsul 2*12 iar rezultatul 24 se va imparti apoi la 3 obtinandu-se 8 adica rezultatul corect. Neacordarea atentiei cuvenite ordinii de efectuare a operatiilor poate duce uneori la rezultate eronate. Implementarea ciclurilor cu contor In rezolvarea unor probleme apare frecvent necesitatea repetarii unei procesari asupra unui numar cunoscut de seturi de date. Astfel valoarea rezultata este 0. O alta varia nta ar fi explicitarea ordinii dorite a efectuarii operatiilor prin folosirea parantezelor: x/(y*z) In acest caz se efectueaza intai operatiile din paranteze adica se inmulteste y cu z iar apoi variabila x este impartita la rezultatul astfel obtinut. Astfel avand in vedere ca expresia 2/3 fiind o expresie cu termeni intregi. Pentru a implementa un astfel de ciclu trebuie sa stabilim urmatoarele: ¾ numele variabilei contor ¾ valoarea initiala a variabilei contor ¾ valoarea cu care variabila contor este incrementata/decrementata dupa fiecare ciclare (pasul) ¾ valoarea finala a variabilei contor. rezultatul obtinut va vi 0 deoarece operatiile efectuandu-se una cate una. 2. Dupa fiecare procesare aceasta variabila este incrementata astfel ca in functie de valoarea acesteia se poate determina daca mai sunt date de procesat.PROGRAMARE IN JAVA .

while(contor <= 10){ System. intr-o singura instructiune: ...4 – Ciclu cu contor Acest algoritm poate fi implementat in Java folosind structura de control repetitiva while ca in programul din exemplul de mai jos: class CicluCuContor{ public static void main(String[] arguments){ int contor = 1. momentul in care conditia de ciclare contor<= 10 nu mai este satisfacuta. variabila contor folosita in programul nostru pentru a tine evidenta numarului de procesari a fost initializata cu valoarea 1. . } } } Asa cum am stabilit. .out.. System.println(contor).. Procesarea se repeta pana cand variabila contor atinge valoarea 11. System.println(contor). contor++. Tinand cont de proprietatile operatorului de postincrementare. Figura 3. contor++.out.println(contor++).34 CURS 3 Ca exemplu sa proiectam algoritmul care asigura calculul si afisarea valorilor de la 1 la 10. programul poate fi simplificat comasand instructiunile: .. Schema logica a algoritmului este redata in figura 3. La fiecare procesare valoarea acestei variabile este afisata dupa care aceasta este incrementata cu 1 (pasul de incrementare este 1)..out.. .4..

Se presupune ca initial fiecare variabila contine valoarea 10: a) produs *= x++.5 . while(contor <= 10) System. %. declararea variabilelor. Programul in aceasta versiune devine ceva mai compact: class CicluCuContor{ public static void main(String[] arguments){ int contor = 1. --. float. ¾ Au fost prezentati operatorii aritmetici +. 2.java Sumar ¾ Pe parcursul acestui curs am tratat problemele fundamentale privind tipurile elementare de date ale limbajului Java.PROGRAMARE IN JAVA . /.Compilarea si executia aplicatiei CicluCuContor. operatorul de concatenare al sirurilor +. Gasiti si corectati erorile din instructiunile de mai jos: a) while(c <= 10){ produs *= c. *. Figura 3. ++. String si boolean.Note de curs 35 Intr-adevar. /= si %=. b) fractie /= ++x. aici. valoarea variabilei contor este intai afisata si abia dupa aceia aceasta este incrementata. fiind folosit operatorul de postincrementare. ¾ S-a prezentat structura si implementarea unui ciclu cu contor folosind structura repetitiva while. char. utilizarea parantezelor ( ) si operatorul de atribuire =. -. *=. Comenzile de compilare si executie a programului continut de acest fisier precum si rezultatele afisate sunt redate in figura 3. ¾ S-a discutat de asemenea ordinea de efectuare a operatiilor si precedenta operatorilor in evaluarea expresiilor. } } Programul va fi editat in fisierul CicluCuContor. Exercitii 1. +=. .println(contor++). Determinati valorile fiecarei variabile dupa efectuarea calculelor. ++c. operatori si utilizarea lor in expresii.5. -=. ¾ Tipurile de date discutate au fost int.java.out.

while(x <= 10){ y= x*x. CURS 3 c) int x = 1. total +=y. ++x.} 3.out. } } . total. total = 0. System.println(y).out. x =1.36 b) if(x > 10) X += 3++. ++x. } System.println(“Total =”+total). Ce va afisa programul urmator: class Mister{ public static void main(String[] arguments){ int y. while(x <= 10){ total += x.

println(Math. Comenzile de compilare si executie a programului continut de acest fisier precum si rezultatele afisate sunt redate in figura 6.random()). Programul urmator genereaza 10 astfel de valori aleatoare: class RandomTest{ public static void main(String[] arguments){ for(int i=1. Figura 6.. Numarul 6 folosit pentru ajustarea valorii generate de metoda random se numeste factor de scalare.Compilarea si executia aplicatiei RandomTest.i<=10. Solutia in acest caz este de a calcula valorile necesare pe baza valorilor aleatoare generate de metoda random. De exemplu pentru a simula rezultatele aruncarii unui zar.out. Comenzile de compilare si executie a programului continut de acest fisier precum si rezultatele afisate sunt redate in figura 6. .i++) System. val = 1+(int) (Math. valorile trebuie sa fie intregi si sa se gaseasca in domeniul [1. } } Programul va fi editat in fisierul RandomTest..2. Aceasta metoda genereaza o valoare aleatoare de tip double. In cazul zarului noile valori se vor calcula cu instructiunea: .. Programul urmator va simula “aruncarea“ de 10 ori a unui zar.Note de curs 61 Curs 6 Generarea numerelor aleatoare Vom studia in continuare metoda random a clasei Math.6]. Programul va fi editat in fisierul Zar.PROGRAMARE IN JAVA .1).java.1. n ∈[0.java.1.. . valorile generate de aceasta metoda nu se gasesc in plaja de valori dorita de programator.random()*6).java De regula.

frecventa6=0. System. System.println(5+”\t”+frecventa5). System.out. System. System. vom executa programul urmator care simuleaza aruncarea de 6000 de ori a unui zar si calculeaza frecventa de aparitie a fiecarei valori. switch(val){ case 1: frecventa1++.out. } } System. case 5: frecventa5++. System. frecventa5=0.java Pentru a ne convinge ca probabilitatea de aparitie a oricarui numar din cele 6 posibile este egala.i++){ val = 1+(int) (Math.2.out.out.println(6+”\t”+frecventa6). break.i++){ val = 1+(int) (Math.Compilarea si executia aplicatiei Zar.out.62 CURS 6 class Zar{ public static void main(String[] arguments){ int val. case 4: frecventa4++. } } .println(“val\tfrecventa”).i<=10. } } } Figura 6. case 3: frecventa3++. case 6: frecventa6++.random()*6).println(2+”\t”+frecventa2). for(int i=1.println(4+”\t”+frecventa4).println(val). frecventa3=0.out. int frecventa1=0. break. System.i<=6000. break. class ZarTest{ public static void main(String[] arguments){ int val. break. break.random()*6). for(int i=1.println(3+”\t”+frecventa3).println(1+”\t”+frecventa1). break.out. case 2: frecventa2++.frecventa2=0.out.frecventa4=0.

static final int ARUNCARI=6000.out.Note de curs 63 Programul va fi editat in fisierul ZarTest.3.Compilarea si executia aplicatiei ZarTest. Constante si variabile globale Rescriind programul din exemplul anterior sub forma modulara am obtinut: class ZarTest{ static int frecventa1=0.java constatam ca de fiecare data obtinem o alta secventa de 10 numere aleatoare.out. case 5: frecventa5++.java. } } } static void afisare(){ System. switch(val){ case 1: frecventa1++.println(3+"\t"+frecventa3). System. Comenzile de compilare si executie a programului continut de acest fisier precum si rezultatele afisate sunt redate in figura 6. case 4: frecventa4++.out.i++){ val = 1+(int) (Math. Figura 6. System.out.println("val\tfrecventa").frecventa6=0.println(2+"\t"+frecventa2). case 2: frecventa2++. case 3: frecventa3++. frecventa5=0. break.println(4+"\t"+frecventa4).println(6+"\t"+frecventa6). De asemenea. break.frecventa4=0. case 6: frecventa6++. System. ruland de mai multe ori programul Zar. } .3.out. System. System. break. static void simulareZar(int n){ int val.random()*6).i<=n.frecventa2=0. for(int i=1.out.java Analizand aceste rezultate observam ca frecventa de aparitie valorilor este aproximativ egala ( circa 1000 de apritii ale fiecarei valori).PROGRAMARE IN JAVA . break.println(5+"\t"+frecventa5). System. break.println(1+"\t"+frecventa1).out. frecventa3=0. break.

.frecventa6. Metoda afiseaza frecventele de aparitie ale valorilor 1. La declararea acesteia s-a folosit pe langa declaratia de tip si cuvantul rezervat Java final. De regula. daca ar fi fost declarate in corpul metodei afisare nu ar fi putut fi incrementate de metoda simulareZar fiindu-i necunoscute acesteia. Ele constitue de fapt o zona comuna de memorie pentru toate metodele clasei in cadrul careia au fost declarate. Solutia a constat in declararea lor in afara corpului vreuneia din metodele clasei ZarTest devenind astfel variabile globale pentru metodele clasei ZarTest. variabilele globale din cadrul clasei ZarTest au fost declarate statice din motive pe care le vom discuta ulterior. Figura 6.6. Acelasi lucru este valabil si pentru variabila de tip int ARUNCARI. Aici apar doua elemente noi.Reprezentarea structurii functionale a aplicatiei ZarTest.4..java In aceasta figura au fost reprezentate atat modulele de cod care coopereaza la realizarea procesarilor necesare cat si blocul de memorie comuna repartizata pentru variabilele globale ale aplicatiei. Numarul de aruncari n este parametrul metodei simulareZar.4.. Ca si metodele..6 calculate de metoda simulareZar. Frecventele de aparitie sunt contorizate de variabilele de tip int frecventa1. simulareZar si afisare. Daca aceste variabile ar fi fost locale metodei simulareZar ele nu ar fi acesate de metoda afisare si reciproc. afisare(). Structura functionala a aplicatiei ZarTest.java poate fi reprezentata ca in figura 6. Valoarea unei astfel de variabile se stabileste la declarare si nu mai poate sa fie modificata in timpul executiei programului. Spunem ca ele sunt vizibile pentru toate metodele clasei in care au fost declarate. } } Aici metoda principala main apeleaza doua metode “subalterne”. . Acesta o transforma intr-o variabila read-only adica intr-o constanta.64 CURS 6 public static void main(String[] arguments){ simulareZar(ARUNCARI). pentru claritatea programului. Metoda simulareZar simuleaza aruncarea zarului de n ori si calculeaza frecventele de aparitie ale valorilor 1. (desi nu este obligatoriu) astfel de variabile sunt denumite folosind majuscule pentru a pune in evidenta ca au o valoare fixata – ca sunt constante.

Acest lucru este posibil numai daca in urma acestui apel variabilele sale nu sunt suprascrise prin executarea din nou a codului metodei astfel ca la revenirea din apel.. (n-1) ⋅ n . Astfel codul metodei apelate va prelucra propriul set de variabile fara a altera valorile setului de variabile proprietate a metodei apelante. memoria de date prelucrata de fiecare apel este diferita.Note de curs 65 Variabile automate O variabila este creata in momentul declararii acesteia. Astfel. Astfel de variabile care au o durata de viata limitata se numesc automate. Denumim domeniu de existenta al variabilei portiunea de program in care aceasta variabila exista si poate fi accesata. o metoda se poate apela pe ea insasi. Acest mecanism este valabil nu numai pentru variabilele declarate in corpul unei functii ci si pentru orice variabila declarata in cadrul unui bloc de instructiuni ( incadrat de acolade ). variabilele locale ale metodei apelante nu mai contin valorile pe care le contineau inainte de apel. Astfel. Acest mecanism consta in apelarea succesiva a unei metode de catre ea insasi.PROGRAMARE IN JAVA .. o variabila declarata in cadrul unui bloc de instructiuni nu este vizibila din afara blocului fiind insa vizibila din interiorul blocurilor de instructiuni incuibate in blocul respectiv. desi codul executat la fiecare apel recursiv este acelasi. Ele sunt create automat la executia blocului de instructiuni care constitue corpul metodei in care au fost declarate si sunt distruse automat la iesirea din blocul respectiv de instructiuni. Din acest motiv valoarea continuta de o variabila automata la creere este arbitrara si trebuie sa fie explicit initializata inainte de a fi folosita. fiecare apel recursiv va crea un nou set de variabile locale propriu. Ele insa sunt distruse prin eliberarea blocurilor de memorie alocata. Deoarece. Variabilele locale ale unei metode sunt create in momentul in care aceasta este apelata si incepe sa fie executata. incetand sa mai existe in momentul in care executia metodei inceteaza. asa cum am vazut variabilele automate sunt create la apelul metodei si distruse la terminarea executiei. Acest bloc de memorie este asociat de catre compilator cu identificatorul (numele) variabilei si este accesat (inscris/citit) prin intermediul acestuia. la revenirea in metoda apelanta. Acest domeniu este stabilit de cateva reguli stricte. Factorialul este definit prin produsul: n!=1 ⋅ 2 ⋅. La creerea variabilei ei i se aloca un bloc de memorie dimensionat sa pastreze date de tipul specificat la declararea variabilei. Recursivitate Existenta variabilelor automate permite implementarea in limbajul java recursivitatii. Portiunea de program in care o variabila poate fi accesata se numeste domeniu de vizibilitate a variabilei. Ca o consecinta a acestui mecanism valorile continute de variabilele locale nu se pastreaza de la un apel la altul al metodei nefiind garantat ca la al doilea apel i se va aloca acelasi bloc de memorie ca la primul apel sau ca acel bloc nu a fost intre timp folosit de o alta variabila la executia unei alte metode. Asa cum o metoda poate apela o alta metoda. Sa exemplificam cele prezentate mai sus prin rezolvarea urmatoarei probleme: Sa se elaboreze un program care sa calculeze si sa afiseze valoarea factorialului numarului 10.

Compilarea si executia aplicatiei FactorialIterativ.66 CURS 6 O prima abordare ar fi utilizarea unui algoritm iterativ la calcularea acestui produs.java Sa vedem acum in figura 6. return fact. Figura 6.Algoritmul iterativ de calcul al factorialului Programul Java care implementeaza acest algoritm folosind o structura repetitiva for este: class FactorialIterativ{ static int factorial(int n){ int fact=1.5 Figura 6. Acest algoritm se bazeaza pe faptul ca formula de calcul a factorialului poate fi scrisa si intr-o forma recurenta: . } } Programul va fi editat in fisierul FactorialIterativ.6.out. for(int k=1. Comenzile de compilare si executie a programului continut de acest fisier precum si rezultatele afisate sunt redate in figura 6. Algoritmul propus este reprezentat prin schema logica din figura 6.5.println(“10! =”+factorial(10)). } public static void main(String[] arguments){ System.6.k++) fact *= k.java.k<=10.7 cum arata schema logica a algoritmului recursiv de calcul al factorialului.

} } Programul va fi editat in fisierul FactorialRecursiv. } public static void main(String[] arguments){ factorial(10). Pentru a efectua acest produs trebuie sa calculez mai intai cat este (3-1)!. Intrucat n==3 este diferit de 1.7. Doresc spre exemplu sa calculez 3!. if(n==1) fact=1. Comenzile de compilare si executie a programului continut de acest fisier precum si rezultatele afisate sunt redate . Intr-adevar 3!=3*2*1. Acum pot sa ma intorc la calculul produsului precedent si sa il efectuez.Note de curs 67 n! = (n-1)! ⋅ n Figura 6. Intrucat 2-1 este egal cu 1. else fact=n*factorial(n-1). System.java. Obtin (3-1)!=2*1=2. Pentru aceasta aplic acelasi algoritm. voi calcula 3! ca fiind produsul dintre 3 si factorialul lui (3-1) . conform algoritmului.out. Pentru aceasta aplic acelasi algoritm.PROGRAMARE IN JAVA . Aceasta este valoarea rezultata pentru 3!. Programul Java care implementeaza acest algoritm folosind o structura de selectie if/else este: class FactorialRecursiv{ static int factorial(int n){ int fact. Avand aceasta valoare pot sa ma intorc cu inca un pas si sa calculez produsul 3*(3-1)! = 3*2=6. Deoarece 3-1 este 2 iar 2 este diferit de 1.println(n+"! ="+fact).Algoritmul recursiv de calcul al factorialului Algoritmul se bazeaza pe urmatorul mecanism. voi calcula (3-1)! ca fiind produsul dintre 2 si (2-1)!. Pentru a efectua acest produs trebuie sa calculez mai intai cat este (2-1)!. (2-1)! este 1. return fact.

In aceste conditii.pentru noi seturi de variabile locale). ¾ Algoritmii iterativi se construiesc folosind structuri de control repetitive (for. Figura 6. ¾ Atat in cazul algoritmilor iterativi cat si in cazul celor recursivi incetarea repetitiei se face in urma unui test de terminare.8. sa nu se termine niciodata. La implementarea unui astfel de algoritm programul care il implementeaza se va “bloca” fiind executat la nesfarsit daca algoritmul este iterativ sau va duce la depasirea spatiului de memorie maxim repartizat programului (prin alocari succesive de memorie . in cazul algoritmilor iterativi aceasta se realizeaza explicit prin utilizarea unei structuri repetitive. while.la fiecare recursie .8.Compilarea si executia aplicatiei FactorialRecursiv. este posibil ca atat ciclul iterativ cat si recursia sa fie infinite. Analizand rezultatele afisate de acest program vedem ca metoda factorial s-a autoapelat de 10 ori si abia dupa aceia. In cazul algoritmilor recursivi repetarea se realizeaza prin apeluri succesive ale metodei.java Pe baza celor doua exemple prezentate putem face o comparatie intre algoritmii recursivi si cei iterativi. cand n a devenit 1 a inceput sa intoarca valorile calculate care au fost afisate incepand cu primul factorial calculat complet (1!) si terminand cu ultimul (10!). Din cele de mai sus putem trage concluzii: ¾ Algoritmii recursivi sunt mai lenti (bazandu-se pe apeluri repetate a unei metode operatie ce necesita un timp relativ lung in comparatie cu executia unei instructiuni de calcul) ¾ Algoritmii recursivi solicita mai multa memorie decat algoritmii iterativi. Recursia se incheie cand este detectat un caz de baza pentru care se cunoaste valoarea ce trebuie returnata. do/while).68 CURS 6 in figura 6. . La algoritmii iterativi repetarea se termina cand invariantul ciclului capata valoarea false. in cazul unor erori de logica in proiectarea algoritmului. ¾ Algoritmii recursivi sunt mai periculosi putand duce la blocarea intregului sistem prin depasirea spatiului de memorie maxim admis. ¾ Amandoua categoriile de algoritmi se bazeaza pe repetarea unei anumite procesari pana la obtinerea rezultatului dorit.

Compilarea si executia aplicatiei Supradefinire. Calculatoarele pot insa prelucra informatii apartinand nu numai domeniului matematici. System.println(a ”^2 =”+patrat(a)). float b=2.out. algoritmii iterativi sunt preferabili celor recursivi.println(b ”^2 =”+patrat(b)).Note de curs 69 Supradefinirea metodelor In aceste conditii.java. prelucrand date ce modelau obiecte specifice acestui domeniu. ordine sau tip). Exista astfel programe de gestiune a bazelor de date care prelucreaza informatii privind inventarul unor obiecte sau gestioneaza personalul unei intreprinderi clientii unei firme sau pacientii unui spital. La apelul metodei.5. Una din aceste metode are ca parametru o valoare de tip int si intoarce un rezultat de tip int. Figura 6.out. compilatorul Java va identifica dupa setul de valori transmis ca parametri (parametrii actuali ai metodei)catre care din metodele cu acelasi nume sa directeze apelul.9. In programul din exemplul urmator cele doua metode numite patrat realizeaza operatia de ridicare la puterea a 2-a a unei valori.java Structuri de date Programele elaborate de noi pana acum rezolvau probleme de natura computationala.9. } public static void main(String[] arguments){ int a=5. A doua metoda patrat are ca parametru o valoare de tip double si intoarce un rezultat de tip double. } static double patrat(double x){ return x*x. La rezolvarea unei probleme date se va apela la un algoritm recursiv numai in cazul in care un algoritm iterativ nu este evident. Datele prelucrate de astfel de . } } Programul va fi editat in fisierul Supradefinire. Acest mecnism se numeste supradefinire. Supra definirea se foloseste de regula pentru a declara un grup de metode care efectueaza aceeasi proocesare dar asupra unor date de tipuri diferite. System. Limbajul Java permite ca mai multe metode sa fie declarate folosind acelasi identificator (nume) cu conditia ca ele sa fie diferentiate prin setul de parametri(parametrii metodelor respective sa difere ca numar.PROGRAMARE IN JAVA . class Supradefinire{ static int patrat(int x){ return x*x. Comenzile de compilare si executie a programului continut de acest fisier precum si rezultatele afisate sunt redate in figura 6.

Astfel pentru date de gen nume. O astfel de grupare cu structura eterogena (formata din date de tip diferit) se numeste structura de date. Alocarea unui ploc de memorie . etc. vechimea. similar tipurilor primitive de date. varsta se poate folosi tipul int. materialului sau a persoanei. salariul. int capacitate. functia. initial aceasta variabila are valoarea null deoarece inca nu refera nici un bloc de memorie. declararea unei variabile de tipul respectiv nu duce si la alocarea memoriei necesare stocarii informatiilor privind atributele obiectului. starea civila. pret unitar. Pentru numar de ore lucrate. Ea modeleaza in program. culoarea. In cazul gestiunii stocurilor informatia ar consta din denumire. denumire. adresa. In Java gruparea unor date intr-o structura se poate face in cadrul unui modul separat prin declaratiei unei clase ca in exemplul de mai jos: public class Automobil{ String tip. Pentru o mai buna claritate din punct de vedere conceptual a programelor. nu va aloca memorie pentru stocarea datelor privind tipul. In cazul claselor.70 CURS 6 programe au un caracter eterogen trebuind sa modeleze caracteristicile specifice obiectelor sau persoanelor reale. cu precizia necesara. String serie_sasiu. autoturismului meu. Aceste caracteristici pot exprimate folosind tipurile de date primitive deja studiate. Ea descrie de fapt atributele unei clase de obiecte. vechime. int nr_usi. telefon. numarul legitimatiei. numar de inventar. un material din stoc sau o persoana pot fi grupate intr-o singura entitate care poate fi manipulata de program ca un tot unitar. Pentru salariu si pentru cantitate poate fi folosit ipul double. numar legitimatie se poate folosi tipul String. numarul de ore lucrate. Toate aceste date se pot exprima folosind tipurile de date cunoscute. ceea ce justifica utilizarea cuvantului rezervat class si constitue de fapt definirea unui tip nou de data care modeleaza un obiect din lumea reala. Dimensionarea acestui bloc se face pe baza descrierii facute in declaratia clasei (prin sumarea dimensiunii locatiilor de memorie necesare memorarii tuturor componentelor structurii). varsta. String nr_circulatie. toate datele privind un obiect de inventar. adresa. Aceasta descriere este folosita la alocarea de memorie cand se creeaza date de acest tip. Aceasta declaratie de clasa nu se refera de fapt la un automobil anume. Astfel declaratia: Automobil masinaMea. valoarea de inventar. continand doar caracteristicile specifice obiectelor din categoria automobilelor. cantitate. String culoare. In cazul unui salariat informatia cu privire la acesta ar putea fi numele. De exemplu informatia privind un obiect de inventar ar putea cuprinde urmatoarele denumirea. telefon. Evident ca pentru a memora atributele unui obiect real intr-o data de acest tip este nevoie de un bloc de memorie suficient de mare pentru a putea stoca toata informatia privind obiectul. Aceasta deoarece variabila masinaMea nu este chiar bloculd de memorie ci o referinta la un bloc de memorie. } Declaratia clasei ca fiind publica permite accesul unei metode din exteriorul modulului la datele “incapsulate” in ea. boolean inmatriculat. caracteristicile obiectului de inventar. numarul de inventar.

masinaMea. Alocarea dinamica de memorie asigura folosirea rationala a acesteia. String culoare. System.marca="Dacia". .PROGRAMARE IN JAVA . Primul modul consta din clasa Automobil definita in fisierul Automobil. Operatorul va intoarce referinta la blocul de memorie dimensionat pe baza tipului specificat ca argument. Un astfel de mod de alocare a memoriei se numeste alocare dinamica.tip = “Dacia”.java: class Structura{ public static void main(String[] arguments){ Automobil masinaMea = new Automobil(). Astfel.println("Masina mea").. . compilatorul a detectat referirea la clasa Automobil. masinaMea.out.java in directorul curent (. Acesta are ca argument tipul de data care urmeaza sa fie continut de blocul de memorie alocat. masinaMea.10. Deci pentru a aloca memorie pentru pastrarea atributelor autoturismului meu.culoare). in momentul in care blocul de memorie nu mai este necesar..java.capacitate). System.out.println("marca:"+masinaMea. acesta este disponibilizat putand fi alocat pentru satisfacerea altor cereri..capacitate = 1300.out. De asemenea blocul de memorie este automat eliberat la distrugerea variabilei referinta. accesul la elementele structurii se face prin numele variabilei referinta urmat de operatorul deacces si numele atributului accesat: . masinaMea. } Al doilea modul este constituit din clasa Structura care contine metoda main().\\)si l-a compilat automat ca facand parte din aplicatie. Programul care exemplifica definirea si utilizarea structurilor de date este prezentat in continuare. masinaMea.capacitate = 1300. System. trebuie folosita secventa : Automobil masinaMea= new Automobil().marca). } } Comenzile de compilare si executie a programului continut de aceste fisiere precum si rezultatele afisate sunt redate in figura 6.println("culoare:"+masinaMea.culoare=”Alb13”. El este alcatuit din doua module.java: public class Automobil{ String marca. masinaMea. Codul acestei clase este continut de fisierul Structura.culoare="Alb 13".println("capacitate:"+masinaMea. System. Ca urmare a cautat fisierul Automobil.out. Se observa din listing ca la comanda de compilare a fisierului Structura.Note de curs 71 se face cu operatorul new. prin simpla atribuire a valorii null variabilei referinta. int capacitate..

11. ¾ in finalul cursului s-a definit conceptul de structura de date si s-a exemplificat modul de implementare si utilizare a structurilor de date in limbajul Java. globale si constante..pow(raza. 14. .PI*Math. 7. 8.72 CURS 6 Figura 6.4) calculeaza si intoarce valoarea 3*3*3*3 = 91. Valorile razei vor fi aleatoare. int exponent) care calculeaza si intoarce valoarea : bazaexponent De exemplu putereIntreaga(3. c) 6. a) 2. ¾ s-a definit si exemplificat modul proiectarea algoritmilor recursivi si s-au comparat performantele acestora in comparatie cu algoritmii iterativi ¾ s-a prezentat mecanismul de supradefinire a metodelor in limbajul java si s-a exemplificat utilitatea acestui mecanism. Elaborati o metoda int putereIntreaga(int baza. 22. .3). ¾ am abordat aspecte legate de domeiul de definitie si de vizibilitate a variabilelor. 18. ¾ s-au discutat tipurile de variabile automate. 6. 5.. b) 3. situandu-se in domeniul [5... volum = (4/3)*Math. Exercitii 1.java Sumar In cadrul acestui curs am abordat urmatoarele probleme ¾ utilizarea metodei random a clasei Math pentru generarea numerelor aleatoare. 10. S-a prezentat si operatorul new si mecanismul alocarii dinamica a memoriei. 3. Am elaborat un program prin care am testat repartizarea uniforma a probabilitatii de aparitie a valorilor generate de functia random. S-a prezentat modul de scalare a acestor valori pentru a se incadra intr-un anumit domeniu. 10.Compilarea si executia aplicatiei Structura. Pentru fiecare set de numere de mai jos scrieti cate o singura instructiune care genereaza la intamplare si afiseaza unul din numerele setului. Elaborati un program Java care calculeaza si afiseaza volumul a 10 sfere folosind instructiunea: .10.25]. 2. 4.9.

care specifica numarul locatiei la care se face accesul: <nume tablou>[<index>] In figura 8.length contine valoarea 10. obiectul tablou mai are in componenta variabila membru length (lungime) continand dimensiunea (numarul de elemente) tabloului. Figura 8.Structura unui tablou cu 10 elemente Pe langa memoria alocata elementelor. . Sintaxa instructiunii de declarare a unui tablou este: <tip> <nume>[] = new <tip>[<lungime>]. Accesul la o anumita locatie se face prin intermediul numelui tabloului si a unui index intreg cuprins intre paranteze drepte.1.PROGRAMARE IN JAVA ... astfel in cazul tabloului din exemplul nostru.. Clasa Array defineste de fapt un grup de locatii succesive de memorie in care vor fi stocate date.Note de curs 85 Curs 8 Tablourile Java prevede o clasa “prefabricata” Array (tablou) de obiecte care implementeaza o structura de date compusa din mai multe elemente de acelasi tip.. .1 este prezentat un exemplu al unui tablou cu 10 elemente. x. Pentru a declara tabloul din exemplul de mai sus vom folosi deci instructiunea: . int x[] = new int[10].

java cu acest modul editat intr-un nou fisier Stack.length.}//intoarce varful stivei } Inlocuind fisierele Register.class.class care la randul sau va incerca sa incarce modulul Stack. Acum vom edita fisierul Stack. } public double pop(){//coboara stiva double val=reg[0].java programul CalcTest va functiona fara sa-i aducem modificari si fara a modifica nici modulul din Calculator.i++) reg[i]=0.86 CURS 8 Aceasta instructiune contine de fapt in prima parte declararea unei variabile de tip referinta la un obiect tablou iar in a doua parte alocarea de memorie pentru acest obiect.i>0. } public double top(){return reg[0].// Alocarea de memorie . interpretorul va semnala eroarea (clasa Stack nu este definita) si isi va inceta activitatea..registrul x reg[1] – registrul y reg[2] . Elementele tabloului vor corespunde celor 4 registri astfel: reg[0] . Operatia a decurs similar inlocuirii unui procesor pe placa de baza cu altul de acelasi tip (compatibil la nivel de pini) dar mai performant.i<reg. Putem deci sa descompunem instructiunea in doua: .2 demonstraeaza acest lucru. Acest exemplu demonstreaza cat de usor pot fi facute modificari in programele proiectate orientat pe obiecte. Vom folosi un tablou reg pentru realizarea unei noi versiuni a clasei Stack elaborata in cursul precedent..i--) reg[i]=reg[i-1].0 return val.i++) reg[i]=reg[i+1]. pop si top vor fi adaptate pentru a lucra cu noua structura de date: class Stack{ private double reg[]. Deoarece nu il gaseste fiind sters.. for(int i=0. reg[0]=val. Schimbarea unei componente cu alta mai performanta dar compatibila la nivel de interfata nu a necesitat modificari in restul programului pe care nici nu a fost nevoie nici macar sa-l mai recompilam.. Listingul din figura 8. public Stack(){// constructor stiva reg=new double[4].class si Register.class acesta va functiona normal afisand aceleasi rezultatele ca si in versiunea sa precedenta. for(int i=0.length-1.// declararea variabilei de tip refrinta la un tablou de int x = new int[10]. Executand acum programul CalcTest.registrul z reg[3] – registrul t Metodele push.class necesar functionarii modulului Calculator. La incercarea de a executa programul CalcTest. int x[]. reg[3]=0.class.java.java in noua sa versiune si il vom compila rezultand modulul Stack.length –1.class de pe disc. } public void push(double val){// ridica stiva for(int i=reg.i<reg.0. De data aceasta stiva va fi implementata folosind un tablou de 4 elemente de tip double. .class acesta va incarca modulul Calculator. Vom sterge in prealabil fisierele Stack.java si Stack.

toString()). Folosind aceasta referinta pot sa accesez variabila membru data a obiectului referit de this.//Afisare obiect b } } Listingul din figura 8.3 ne arata comenzile de editare. . Aceasta referinta este accesibila prin parametrul implicit this. compilare si executie a acestui program. } public toString(){ int data=0. Sa ilustram aceasta printr-un exemplu: Fie clasa: class ThisData{ private int data. return “this.java La instantierea unei clase intr-un obiect acesta este referit printr-o valoare referinta.out.//crearea obiectelor a si b System.2. In cadrul metodei am declarat o variabila locala de acelasi tip int si cu acelasi nume data initializata cu 0. } } Constructorul clasei initiaza variabila data cu valoarea primita ca parametru.println(a. Metoda toString formeaza si intoarce un string continand si data setata de constructor.Note de curs 87 Referinta this Figura 8.PROGRAMARE IN JAVA .data. La apelul oricarei metode aceasta primeste ca parametru implicit referinta la obiectul careia ii apartine metoda.println(b.data =”+this. Metoda toString primeste insa ca parametru implicit referinta this la obiectul din care face parte. b=new ThisData(2).toString()). public ThisData(int val){ data = val. Iata si clasa de testare a acestui mecanism: class ThisTest{ public static void main(String[] arguments){ ThisData a=new ThisData(1).Inlocuirea modulului Stack.out.class in programul CalcTest. Aceasta “mascheaza” in mod normal variabila membru data care astfel devine inaccesibila.//Afisare obiect a System.

0. // Constructori public Timp(){ setTimp(0. } public String toString24h(){ return ora+”:”+(min<10?”0”:””)+min+”:”+(sec<10?”0”:””)+sec. Al doilea aspect priveste returnarea parametrului implicit this de catre metodele setOra.int m.setMin(m). Definim clasa Timp: class Timp{ private int ora. int s){ setOra(h).Testarea parametrului this O alta aplicatie a parametrului this este apelul in lant al metodelor unui obiect.} // Metode public void setTimp(int h.0). .} public int getMin(){return min.3. Valoarea returnata va fi folosita pentru exemplificarea inlantuirii apelurilor acestor metode. setMin si setSec. return this. al treilea aspect priveste prevederea metodelor set si get pentru accesul variabilelor membre private. return this.return this.setSec(s). int s){ setTimp(h. int m.m.} public Timp(int h. min. } } Sunt trei aspecte de subliniat cu privire la definitia acestei clase.} public String toString12h(){ return ((ora==12 || ora==0)? 12:ora%12)+”:”+ (min<10?”0”:””)+min+”:”+(sec<10?”0”:””)+sec+ (ora<12 ?”AM”:”PM”).int m){setTimp(h. sec.0).} public int getSec(){return sec. Aceste metode permit accesul din exterior la variabilele private dar metodele de tipul set efectueaza o validare a datelor inscrise in aceste variabile. } public Timp setMin(int m){ min=((m>=0 && m<60)?m:0).s). return this. Sa o urmarim pe un exemplu.m.0).} public Timp(int h. } public int getOra(){return ora. } public Timp(int h){setTimp(h.88 CURS 8 Figura 8. } public Timp setSec(int s){ sec=((s>=0 && s<60)?s:0). Primul este supradefinirea constructorului Timp. } public Timp setOra(int h){ ora=((h>=0 && h<24)?h:0).0.

folosind explicit operatorul new. System. compilatorul le va aloca automat memorie in momentul in care clasa este incarcata.//Apelul inlantuit System. Intrucat si aceasta intoarce o referinta la t.pow(2.Apelul inlantuit al metodelor Membrii statici ai unei clase In mod normal. Pentru a accesa membrii dinamici trebuiesc create dinamic instante ale clasei.// Apel inlantuit System.println(t. System. se evalueaza de la stanga spre dreapta (operatorul de acces .setSec(30) . La crearea instantelor unei astfel de clase. t.setMin(7).setOra(14) ..println(t.4: Figura 8.toString24h()).5). Este astfel cazul functiei main declarata public static. Blocul de memorie se aloca membrilor statici o singura data. . ale caror metode pot fi apelate fara a crea instante ale acestor clase.toString24h()).4. membrilor dinamici ai acesteia trebuie sa li se aloce memorie folosind operatorul new. Daca totusi membrul unei clase se declara ca fiind static. Accesul membrilor statici ai clasei se face cu operatorul de acces “. la incarcarea clasei.3)).setSec(30). } } 89 Apelul inlantuit: . am vazut ca memoria pentru instantele unei clase se aloca dinamic.PROGRAMARE IN JAVA . O clasa poate sa aibe atat membri statici cat si membri dinamici.20.out.setMin(7).toString12h()).out.” precedat de numele clasei ( de exemplu Math. Astfel intai se executa metoda t.setSec(30).println(“Timp nou:\n”+ t. se asociaza de la stanga la dreapta). Pe de o parte acest mecanism permite accesul acestor membri (daca sunt publici) fara a crea vre-o instanta a clasei.setTimp(20. in final se va executa si t.setOra(14).Note de curs Modulul de test al acestei clase este: class TimpTest{ public static void main(String[] arguments){ Timp t=new Timp().setSec(30). Deci se va executa metoda t.out..toString12h()). Math si System. Numai membrilor statici ale clasei li se aloca memorie si numai acestia pot fi accesati prin intermediul numelui clasei. Listingul compilarii si executiei acestui program este redat in figura 8.setOra(14).println(t. Este de asemenea cazul claselor studiate de noi.. Cele de mai sus sunt valabile si pentru cel de al doilea apel inlantuit din program. Aceasta intoarce o referinta la obiectul t astfel incat in continuare se executa t.setMin(7).setMin(7).20). proprii fiecarei instante create (figura 8. si este comun tuturor instantelor clasei spre deosebire de blocurile de memorie alocate dinamic.. t.out.

In momentul in care acest numar este mai mare sau egal cu 10 nava devine agresiva.i++) flota[i]=new Nava(“Red”+i).actiune(). Rebelii stiu ca un astfel de atac are sanse de succes numai daca numarul lor de nave este mai mare sau egal cu 10. Aceasta variabila este incrementata ori de cate ori in formatie soseste o noua nava (se creaza o noua instanta a clasei Nava).Alocarea statica si dinamica a memoriei pentru membrii clasei Accesul unei metode statice la variabilele dinamice ale unei instante poate fi facut folosind parametrul implicit this .println(nume+“ in formatie”). } public void actiune(){if(nrNave >= 10) ataca(). flota[0]= new Nava(“Red Leader”). for(int i=0. } } class StarWars{ public static void main(String[] arguments){ Nava flota[]=new Nava[10]. fiecare nava trebuie sa cunoasca numarul de nave de care dispune flota Rebelilor. Acest numar poate fi cunoscut tuturor navelor implicate prin prevederea unei variabile comune nrNave. prin urmatorul program: Sa presupunem ca vrem sa scriem un joc in care o flota de nave a Rebelilor intentioneaza un atac asupra unei baza stelare a Imperiului. for(int i=1. accesibile fiecarei instante.5. Pentru a declansa atacul.i<10.out.} private void asteapta(){ System.println(nume + “ ataca baza”).out.nume=_nume.out.90 CURS 8 Figura 8. System.} private void ataca(){System.else asteapta().i<10.println(nume + “ gata de lupta”). private String nume.i++) flota[i]. public Nava(String _nume){ //Constructor nrNave++. Sa exemplificam utilitatea existentei unei zone comune de memorie pentru toate instantele unei clase. class Nava{ private static int nrNave=0.i<10.i++) flota[i]. for(int i=1. } } . deschizand focul asupra bazei stelare.actiune(). Fiecare navaa flotei Rebelilor este modelata de un obiect obtinut prin instantierea clasei Nava.

este mai mic decat 10. Deoarece numarul de nave. Elementele tabloului. Putem defini clase generice care doar sa specifice metodele abstracte de prelucrare a unor date generice (de tip neprecizat) fara a concretiza in ce consta aceasta prelucrare. prin “sosirea” navei amiral. continut de variabila comuna nrNave. numarul lor atinge valoarea necesara declansarii atacului ele intra in lupta in urma apelului in ultimul ciclu for din program a metodei actiune pentru fiecare obiect in parte. Astfel de clase nu pot fi utile la crearea de obiecte dar pot fi folosite in calitate de clase de baza ale caror . nici una din ele nu ataca baza.PROGRAMARE IN JAVA .java.6. Ciclul for urmator apeleaza metoda actiune a fiecarui obiect de tip Nava astfel creat. Acestea sunt mostenirea si polimorfismul. Programarea orientata pe obiecte In aceasta sectiune vom discuta tehnologiile de baza aplicate in programarea orientata pe obiecte (POO). Noile clase “mostenesc” atributele si comportamentul (variabilele si metodele) clasei de baza “imbogatindu-le” cu functiuni si atribute suplimentare ( prin adaugare de noi variabile si metode). Elementele acestui tablou sunt referinte la obiecte din clasa Nava. initializate implicit cu null la creere. Mostenirea este o forma de refolosire a modulelor deja elaborate care permite definirea de noi clase pornind de la o clasa existenta. compilarea si executia programului StarWars Comenzile de editare.Editarea. Abia cand. I cadrul metodei main este declarat un tablou flota de 10 elemente de tip Nava. Codul de testare a clasei Nava este editat in fisierul StarWars. primesc valori in cadrul unui ciclu for pe masura ce noi instante ale clasei Nava sunt create.6.Note de curs 91 Figura 8. compilare si executie a fisierelor programului precum si rezultatele afisate sunt redate in figura 8.

}//Constructorul public void dormi() {System.}//Constructorul public void vorbeste(){System.} } public class Motan extends Mamifer{ public Motan(String nume){super(nume).println(nume +“: Posta!”).vorbeste(). System.} } Aceasta clasa o vom folosi pentru a defini noi clase derivate care mostenesc atributele si comportamentul obiectelor descrise de aceasta clasa dar le extind cu noi atribute si actiuni posibile: public class Dulau extends Mamifer{ public Dulau(String nume){super(nume).dormi(). System.92 CURS 8 subclase sa implementeze prin supradefinire algoritmi concreti pentru metodele respective adecvati procesarii unor tipuri de date concrete. Obiectele obtinute prin instantierea unei subclase sunt considerate si obiecte ale superclasei ceea ce permite de exemple gruparea a mai multor obiecte apartinand unor subclase diferite ale aceeasi superclase intr-un singur tablou de obiecte de tipul superclasei.dormi().out. Vom analiza in continuare pe baza unor exemple folosirea celor doua mecanisme POO in elaborarea programelor. Aceste mecanisme deschid perspective deosebite in ingineria software in ce priveste eficienta in proiectarea si implementarea unor pachete de programe complexe.}//Constructorul public void vorbeste(){System.println(nume +“: ZZZZ ZZZZZZZZ ZZZZ”).dulau. System. motan.println(nume+“: Ham!”).out.println(“Este timpul ca toti sa faca nani. Cele doua mecanisme permit refolosirea eficienta a modulelor software deja elaborate permitand extinderea functionalitatii unei clase de baza (superclase) prin definirea noilor functiuni intr-o clasa derivata (subclasa) fara sa fie nevoie de modificarea codului superclasei.println(“Intai cerem motanului sa vorbeasca:”). Postas postas = new Postas (“Nae”).out. Acest mecanism este numit polimorfism. postas. } } .out.println(“Acum este momentul sa vorbeasca postasul:”). Motan motan = new Motan (“Pacepa”).vorbeste().vorbeste(). dulau.postas. public Mamifer(String _nume){nume = _nume.out.”). Sa folosim aceste clase in programul urmator: class Specii{ public static void main(String[] arguments){ Dulau dulau=new Dulau (“Grivei”).}//Constructorul public void vorbeste(){System. Mostenirea Vom defini in continuare o clasa Mamifer: public class Mamifer{ public String nume.} } public class Postas extends Mamifer{ public Postas(String nume){super(nume). System.out.println(nume +“: Miau!”).} } Constructorii aceste subclase invoca constructorul superclasei referit de super.out. motan.dormi().out.println(“Iar acum sa vorbeasca dulaul:”).

1/x.pop())).push(Math.display().//apelul constructorului superclasei } public void cs(){s.class obtinut din compilarea acesteia.display().push(Math.} public void inv(){s.display(). Membrii declarati protected ai superclasei vor fi accesibili din subclase si inaccesibili din afara clasei de baza si a claselor derivate din aceasta.pop())).pow(s. EXP .PROGRAMARE IN JAVA . Programatorul nici nu trebuie sa dispuna de codul sursa al superclasei ci numai de modulul . Sa folosim acest mecanism pentru a extinde functiunile calculatorului stiva elaborat in cursul trecut transformandu-l intr-un calculator stiintific definit de clasa CalculatorSt. Figura 8.pop())).} public void log(){s. POW . SQR .} public void sqr(){ double a= s. Vom realiza aceasta prin adaugarea urmatoarelor operatii:CS – schimbarea semnului.} public void exp(){s.sqrt(s.s. INV .display().7. Pentru ca totusi sa –i putem accesa din subclasele derivate se va folosi specificatorul protected.display().push(Math. Aceasta este singura modificare pe care trebuie sa o aducem clasei Calculator si ea se datoreste numai necunoasterii de catre noi la momentul elaborarii acesteia a specificatorului de acces protected.exp(s.ln(x). s.x1/2.} } Se vede ca aceasta clasa foloseste in noile metode adaugate accesul la stiva s si la metoda display a superclasei Calculator.push(-s. } public void pow(){s.pop().pop())). Vom putea acum sa scriem un program care sa calculeze o expresie continand si functiile implementate mai sus cum ar fi: -9 ⋅ 52 + e2⋅5 . Aceasta ridica o problema deoarece acestti membri ai superclasei au fost declarati privati si deci nu pot fi accesati din afara clasei.7. LOG .log(s.push(Math. class CalculatorSt extends Calculator{ public CalculatorSt(){// Constructorul super(). Nu este bine sa-i declaram publici din motivele enuntate la momentul respectiv.ex.pop()). SQRT .Comenzile de compilare si executie programului Specii Pentru definirea unei subclase nu trebuie modificat si deci nici recompilat codul superclasei.pop()).push(a*a).} public void sqrt(){s.pop().x2.Note de curs 93 Comenzile de compilare si executie a fisierelor programului precum si rezultatele afisate sunt redate in figura 8.display().display(). In mod normal superclasa trebuie astfel proiectata incat sa nu necesite modificarea si recompilarea codului sursa.push(1/s.xy.

mul().c. } } Comenzile de compilare si executie a fisierelor programului precum si rezultatele afisate sunt redate in figura 8. c.enter(9).}//Constructorul public void dormi() {System. La apelul metodei vorbeste a elementelor tabloului va fi .8.exp().mul().94 CURS 8 Programul care efectueaza calcul acestei expresii folosind o instanta a aceastei clase derivate este: class CalcStTest{ public static void main(String[] arguments){ CalculatorSt c = new CalculatorSt().println(nume +“: Posta!”). am adaugat clasei de baza metoda abstracta vorbeste fara insa a concretiza implementa algoritmul concret al acestei actiuni. Stiind ce comportament general vor avea obiectele din aceasta clasa o putem defini astfel: abstract public class Mamifer{ public String nume.}//Constructorul public void vorbeste(){System.enter(5).println(nume+“: Ham!”).} } public class Postas extends Mamifer{ public Postas(String nume){super(nume).println(nume +“: ZZZZ ZZZZZZZZ ZZZZ”).}//Constructorul public void vorbeste(){System. Aceasta metoda abstracta va fi definita concret in fiecare subclasa derivata: public class Dulau extends Mamifer{ public Dulau(String nume){super(nume). numai ca o vor face fiecare in felul specific subclasei careia ii apartin.out. c.Comenzile de compilare si executie programului CalcStTest Polimorfismul In sectiunea anterioara am definit clasa Mamifer al carui scop nu era creerea de obiecte ci de a servi ca baza pentru definirea unor clase derivate.c.cs().sum().}//Constructorul public void vorbeste(){System.7.out.} abstract public void vorbeste().println(nume +“: Miau!”).out. c.c. } Stiind ca obiectele din toate subclasele derivate vor “vorbi”.} } public class Motan extends Mamifer{ public Motan(String nume){super(nume).} } Obiecte apartinand acestor subclase pot fi grupate toate intr-un tablou cu elementele de tip Mamifer.c.sqr().c.enter(5). c. Figura 8. public Mamifer(String _nume){nume = _nume.// constructor c.enter(2).out.

Decizia asupra retragerii va fi luata de fiecare nava in parte prin evaluarea la comanda actioneaza a variabilei nrNave. O clasa declarata finala nu mai poate fi folosita ca superclasa pentru derivarea unor subclase. In acest fel valoarea variabilei nu mai poate fi modificata ramanand constata pe tot parcursul executiei programului.i<3. personaje[2] = new Postas (“Nae”). System. Daca un obiect din aceasta clasa este distrus. numarul de nave al flotei continut de variabila comuna (statica) nrNave va fi decrementata. System. public void finalize() si vom simula distrugerea unor nave prin atribuirea valorii null referintelor catre obiectele care le modeleaza. Clase si metode finale Am vazut ca variabilele membre ale unei unei clase pot fi declarate finale folosind specificatorul final. putand fi supradefinit de programator daca este cazul.out. personaje[1].out.7). Ca si constructorul clasei aceasta nu trebuie neaparat declarata. personaje[1]= new Motan (“Pacepa”). flota se va retrage.Note de curs 95 automat detectata subclasa careia ii apartine obiectul si va fi apelata metoda corespunzatoare: class SpeciiNoi{ public static void main(String[] arguments){ Mamifer personaje[]=new Mamifer[3].dormi(). Cu alte cuvinte.println(“Acum este momentul sa vorbeasca postasul:”). metoda public void finalize() a unei clase nu poate fi supradefinita.println(“Iar acum sa vorbeasca dulaul:”).”). Asa cum constructorul clasei exista implicit si are numele clasei. Ca exemplu vom modifica clasa Nava care definea comportamentul navelor spatiale ale flotei Rebelilor.vorbeste(). Spre deosebire de constructori. Si clasele pot fi declarate finale. } } Programul va afisa aceleasi rezultate ca si cele obtinute de programul Specii (figura 8. Finalizatori Distrugerea unui obiect al unei clase se poate face prin atribuirea valorii null referintei catre acesta. si finalizatorul clasei se va defini numai daca sunt necesare niste procesari inainte de “decesul” obiectului.vorbeste().out.out.vorbeste(). personaje[0]=new Dulau (“Grivei”). for(int i=0.println(“Este timpul ca toti sa faca nani.println(“Intai cerem motanului sa vorbeasca:”). ea nu mai poata fi mostenita. Vom adauga deci clasei Nava metodele private void pleaca(). In acest mod aceste metode nu mai pot fi supradefinite intr-o subclasa derivata.i++) personaje[i]. Putem aplica specificatorul final si metodelor unei clase. nu are parametri nu face nimic si nu intoarce nimic. Blocul de memorie alocat obiectului va fi astfel eliberat si va fi colectat de interpretor pentru a fi folosit la alte cereri de alocare de memorie.PROGRAMARE IN JAVA . . personaje[0]. Metodele declarate de tip static si/sau private sunt implicit finale. System. Inainte de a “muri” interpretorul va executa automat metoda finalize() care este publica si de tip void (nu intoarce nimic). System. O clasa nu poate avea decat un singur finalizator. Daca numarul de nave in timpul atacului scade sub 8. personaje[2].

Chiar si asa daca analizam rezultatele afisate la executia programului (figura 8.i<10. System. for(int k=0..9) observam ca aceasta colectare este efectuata cu o oarecare intarziere – pe la mijlocul pasului urmator al ciclului for .k++){ for(int i=0.out. ataca(). else if(nrNave >= 10){ inAtac=true.println(nume + " se retrage"). } private void retragere(){ System.gc().. private String nume.out.actiune().} private void asteapta(){ System..k<3. private boolean inAtac=false. Daca colectarea blocurilor de memorie eliberate nu s-ar forta prin acest apel. for(int i=1.i<10.println(nume+" in formatie").i++) if(flota[i]!=null)flota[i].i++) flota[i]=new xWing("Red"+i). flota[0]= new xWing("Red Leader"). retragere(). System. }else asteapta(). }else ataca(). System. } } class StarWars2{ public static void main(String[] arguments){ xWing flota[]=new xWing[10]. } } } In acest program.out.nume=_nume.96 CURS 8 class xWing{ private static int nrNave=0. oride cate ori o nava este distrusa ( se atribuie referintei catre obiectul care o modeleaza valoarea null ).gc(). } private void ataca(){System. este solicitata expres colectarea memoriei eliberate cu instructiunea de apel a metodei gc() (garbage collection – colectarea gunoiului in engleza) a clasei System: . } public void actiune(){ if (inAtac) if( nrNave<9){ inAtac=false.. .out. System.out.println(nume + " ataca baza"). flota[k]=null. } public void finalize(){ --nrNave. public xWing(String _nume){ //Constructor nrNave++. interpretorul ar fi facut aceasta operatie cand ar fi vrut el (dupa terminarea programului nostru) si nu am fi obtinut efectul scontat.println(nume + " gata de lupta").println("Au mai ramas "+ nrNave +" nave").

Explicatia consta in faptul ca colectarea blocurilor de memorie eliberate este facuta de un task care se executa cvasi-paralel cu taskul programului nostru. ¾ Clasele permit incapsularea daatelor la un loc cu codul in cadrul fiecarei instante a clasei ¾ Specificatorii de acces public si privat permit restrictionarea accesului unui modul utilizator din exterior la membrii clasei (variabile si/sau metode). Vom detalia acest aspect cand vom vorbi despre firele de executie (thread-uri) Sumar Figura 8. ¾ Restrictionarea accesului duce la cresterea sigurantei programului.PROGRAMARE IN JAVA . ¾ Instantele unei clase se numesc obiecte ele putand modela cu precizia dorita obiecte ale lumii reale. nu inaintea acestuia.Note de curs 97 interior.9. Exercitii Elaborati un program Java care folosind clasa Calculator sa calculeaze si sa afiseze expresiile: .Rezultatele afisate la executia programului StarWars2 In cadrul acestui curs am abordat urmatoarele probleme ¾ crearea instantelor multiple ale unei clase prin declararea unor variabile referinta care refera memoria alocata dinamic pentru fiecare insatnta cu operatorul new. ¾ abordarea orientata pe obiecte a elaborarii programelor si aplicarea metodologiei top-down de proiectare creste eficienta in munca de programare.

} public double pop(){//coboara stiva double val=reg[0].sto(val).get()). . In cazul claselor.length.get().i<reg.t.sto(y. public Stack(){ x=new Register(). Prima dintre ele folosea 4 obiecte din clasa Register: class Stack{ private Register x.}//intoarce varful stivei } iar cea de a doua folosea un tablou: class Stack{ private double reg[].i>0.98 CURS 9 Curs 9 Interfete Un principiu de baza in ingineria software il constitue separarea specificatiilor unui modul de implementarea interna a acestuia.get()).get()). y. iterfata este constituita din setul de metode publice ce pot fi apelate de un modul exterior.length –1. z.sto(z.0.sto(0.i++) reg[i]=0. t=new Register(). reg[0]=val.// constructor obiect y=new Register().get()). Fie de exemplu cele doua implementari elaborate de noi ale stivei folosite de clasa Calculator.get(). t. public Stack(){// constructor stiva reg=new double[4]. constituind puntea dintre lumea exterioara si implementarea interna a clasei.get()). y.sto(z. } public void push(double val){// ridica stiva for(int i=reg. z=new Register().get()). for(int i=0.z.0). } public double pop(){//coboara stiva double val=x.sto(y. } public void push(double val){// ridica stiva t.sto(t.sto(x. x.y. z. } public double top(){return x. x. return val.i--) reg[i]=reg[i-1].

} public double pop(){//coboara stiva . implementare clasa Stack . formata din metodele publice pushi. } . implementare interna top . public abstract double pop()....Reprezentarea schematica a obiectelor clasei Stack Am vazut ca pentru proiectarea programului are importanta doar cunoasterea interfetei clasei Stack..0 return val.. Aceste trei metode publice constituie interfata prin care modulele exterioare interactioneaza cu obiectele clasei Stack.i++) reg[i]=reg[i+1]. pop si top. implementare interna push . implementare interna pop . Clasa poate fi folosita si pentru realizarea unor alte implementari ale interfetei..i<reg.. } public void push(double val){// ridica stiva . class Stack extends StackInterface { . Cunoasterea implementarii interne a acestor metode in clasa Stack nu este importanta pentru proiectarea modulelor care folosesc obiecte din aceasta clasa. implementare interna ... Figura 9. Pentru utilizator nu este important daca clasa este implementata folosind componente registre sau un tablou..1..}//intoarce varful stivei } 99 Amandoua variantele pot fi reprezentate ca in figura 9.Note de curs for(int i=0. } public double top(){return reg[0]. } Vom defini clasa Stack ca subclasa derivata din StackInterface: class Stack extends StackInterface{ private double reg[].PROGRAMARE IN JAVA . } public double top(){ . O solutie este folosirea unei clase abstracte: public abstract class StackInterface{ public abstract void push(double val). public Stack(){// constructor stiva . public abstract double top()..1..... reg[3]=0. In cazul celor doua variante insa interfata si implementarea nu sunt separate..... } } Acum dispunem atat de specificatia metodelor publice ale clasei adica definitia interfetei acesteia in clasa abstracta StackInterface si separat de implementarea particulara a clasei definita de clasa Stack.length-1.

double h ){ bMare=b.double _b.out.toString()+”=”+t.out.double h){latime=l. interface Patrulater{ double calculArie(). implementare clasa Stack .println(“Arie “+d. String toString(). public Dreptunghi(double l..bMica=_b. double pop(). inaltime.} public String toString(){ return “Dreptunghi(“+latime+”.10).Compilarea si executia programului Figuri. System.. } Sa exemplificam cele prezentate mai sus printr-un exemplu. System. Programul propus de testare a acestor doua clase este: class Figuri{ public static void main(String[] arguments){ Dreptunghi d=new Dreptunghi(5.”+inaltime+”)”.4).. } Aceasta interfata poate fi folosita la definirea claselor Dreptunghi si Trapez: class Dreptunghi implements Patrulater{ private double latime.inaltime=h.”+inaltime+”)”.calculArie()).5.} public String toString(){ return “Trapez(“+bMare+”. Trapez t=new Trapez(10.} public double calculArie(){return latime*inaltime. Astfel in locul definitiei clasei abstracte StackInterface putem defini explicit o interfata echivalenta: public interface StackInterface{ void push(double val).2.. } } class Trapez implements Patrulater{ private double bMare.toString()+”=”+d.inaltime .100 CURS 9 Limbajul Java ofera insa in locul artificiului declararii unei clase abstracte un mecanism propriu pentru definirea interfetelor.calculArie()). } Acum putem defini o clasa Stack care implementeaza interfata StackInterface si nu extinde prin supradefinirea metodelor clasa abstracta StackInterface ca in cazul precedent. } } Figura 9.java . } public double calculArie(){return (bMare+bMica)*inaltime/2. Vom defini interfata Patrulater. class Stack implements StackInterface { .bMica.println(“Arie “+t. double top(). public Trapez(double b.inaltime=h.”+bMica+”. } } Ambele clase Dreptunghi si Trapez implementeaza (diferit) aceeasi interfata Patrulater.

println(“LUNI”). Interfetele pot contine si variabile statice finale (constante) ca in exemplul urmator: interface ZileSaptamina{ static final int LUNI = 0. case MIERCURI: System.Pensie si Moarte.println(“VINERI”). } } } Listingul compilarii si executiei acestui program este redat in figura 9.out.out. static final int DUMINICA = 6.PROGRAMARE IN JAVA .java Interfete multiple O clasa poate implementa in acelasi timp mai multe interfete ca mai jos: public class ViataMea extends ViataGrea implements Nastere. case DUMINICA: System.break... Unele din aceste metode pot fi mostenite de la superclasa ViataGrea.println(“DUMINICA”)..Note de curs 101 Listingul din figura 9.Pensie. . Somn. case SIMBATA: System. static final int MIERCURI = 2.. daca vreuna din metodele specificate de interfata ramane nedefinita. In caz contrar. Servici. static final int MARTI = 1. static final int VINERI = 4.out. Trebuie facuta o distinctie clara intre clasele abstracte si interfete. case VINERI: System.break. implementare . In cazul implementarii unei interfete.Armata. se va genera o eroare la compilare.out. static final int JOI = 3.. Munca. } class Zi implements ZileSaptamina { public static void main(String[] arguments){ int zi=4..2 ne arata comenzile de compilare si executie a acestui program precum si rezultatele afisate de acesta.println(“MIERCURI”).break. Munca.println(“JOI”).Scoala.out.Scoala.Servici. case MARTI: System. O interfata poate mosteni metodele specificate de la alte interfete: public interface Servici extends Desteptare. static final int SIMBATA = 5.out.Compilarea si executia programului Zi. } Clasa ViataMea trebuie sa prevada definitii pentru toate metodele specificate de interfetele Nastere. } O clasa care implementaeaza interfata Servici va trebui sa defineasca pe langa metodele specificate de aceasta si toate metodele specificate de interfetele pe care aceasta le-a mostenit: Desteptare. clasa trebuie sa prevada obligatoriu definitii pentru toate metodele specificate de aceasta.break. O clasa poate mosteni numai o singura clasa abstracta dar poate implementa mai multe interfete.3. Somn{ .break.break. switch(zi){ case LUNI: System.println(“SIMBATA”).out.3: Figura 9.break.println(“MARTI”).Moarte{ . case JOI: System.

sa ne ocupam de componenta in. Dar de ce sa inventam roata? Pachetul java. Fluxul de date este generat de consola sistemului fiind constituit din perechi de octeti reprezentand codurile caracterelor introduse de la tastatura. Programul poate extrage cate o pereche de octeti de date (codul unui caracter) din flux apeland metoda int read() a obiectului out. programul trebuie sa contina la inceput instructiunea de a incarca clasele predefinite din acest pachet: import java. Am spus atunci ca in cazul in care se detecteaza o eroare la citirea din fluxul de date este generata o exceptie putand fi executata o procedura de tratare a exceptiei respective. Componenta out este o instanta a fluxului standard de iesire date definita in clasa System: .io. etc.. Clasa InputStream prevede si o metoda mai performanta. Clasa InputStream este definita in Java API ca o clasa abstracta. Pentru a ignora exceptiile generate la citire. Ar trebui sa elaboram metode proprii de prelucrare a octetilor preluati din fluxul de date de intrare care sa transformam aceste date primare in valori de tip int. . String. Aceasta citeste octetii in tabloul specificat de referinta b[] si intoarce numarul de octeti extrasi din flux. (Caracterele in Java sunt codificate conform codului Unicode – o extensie pe 2 octeti a codului ASCII). se poate specifica clauza throws.. Aceste trei metode prezentate mai sus nu ofera decat un suport foarte primitiv de introducere a datelor.. . componenta in este o instanta a fluxului standard de intrare date definita in clasa System: . Aceasta este o instanta a clasei InputStream care defineste un flux de date de intrare. Deoarece afisarea prin metodele println si print nu ne-a creat probleme.io. prin supradefinirea metodei read(): int read(byte b[]) throws IOException. static PrintStream out. static InputStream in.io din Java API prevede clase mult mai puternice pentru gestiunea fluxurilor de date de intrare cum ar fi clasa DataInputStream definita ca: class DataInputStream extends FilterInputStream implements DataInput Clasa FilterInputStream este o versiune ne-abstarcta a clasei InputStream definita in java. Am folosit acest mecanism in exemplul din sectiunea “Definirea metodelor” a cursului 5. Pentru a “sari” peste caracterele de control ‘\n’ -“new line” generate de apasarea tastei ENTER am apelat metoda skip() care elimina din fluxul de date urmatoarea pereche de octeti... Intrucat exceptiile generate la operatiile de I/O sunt continute in pachetul java.. Atat PrintStream cat si InputStream sunt obiecte predefinite in Java API.102 CURS 9 Input/output In programele elaborate de noi pana in prezent am folosit pentru afisarea rezultatelor la consola componenta out iar pentru citirea datelor de la consola componenta in a clasei System. double.io din Java API ca: class FilterInputStream extends InputStream ...*. int read() throws IOException. Similar.. ..

out.io. case MARTI: System. data = input.out. case DUMINICA: System.out.out. Avem astfel de exemplu metodele: final boolean readBoolean() throws IOException.print(“Introduceti un numar intreg (0-6):”). final char readChar() throws IOException. } System. short.break.in).break.out. System. if(zi<0 || zi>6) break. final short readShort()throws IOException.out. .break. long.out. switch(zi){ case LUNI: System. In acest program am folosit pentru conversia din String la intreg metoda statica parseInt a clasei predefinite Integer. final String readLine()throws IOException. Rezultatele compilarii si executiei programului sunt prezentate in figura 9.readLine(). case SIMBATA: System.out.println(“VINERI”).println(“SIMBATA”). final double readDouble()throws IOException. Pentru noi este utila in acest caz numai metoda readLine care preia intr-un String toti octetii din fluxul de intrare date.flush(). case JOI: System. float.break.println(“Bye!”). clasa prevede o serie de metode care permit printre altele si citirea din fluxul de intrare date a unor valori de tip byte.println(“JOI”).break.break.Note de curs 103 Interfata DataInput definita tot in java.println(“MIERCURI”).Sa exemplificam utilizarea clasei DataInputStream prin programul urmator: import java. final int readInt()throws IOException. Aici in este un obiect din clasa InputStream.out.println(“LUNI”). Acest grup de cifre este extras din String si convertit la intreg.*. case MIERCURI: System. while(true){ System. } System. Un obiect din aceasta clasa este construit pe baza unui obiect de tipul InputStream transmis ca parametru constructorului: DataInputStream input = new DataInputStream(in).out.println(“MARTI”). boolean si String.parseInt(data). double.println(“DUMINICA”).PROGRAMARE IN JAVA .4. DataInputStream input = new DataInputStream(System. final float readFloat()throws IOException. pana la primul caracter ‘\n’. class Zi implements ZileSaptamina { public static void main(String[] arguments) throws IOException{ int zi. String data. Succesiunea de cifre introdusa de la tastatura si terminata cu ENTER este grupat intr-un obiect de tip String si returnat de aceasta metoda. zi=Integer. final byte readByte() throws IOException.break. Pe langa metodele mostenite de la clasa InputStream pe care le-am discutat deja. char. } } Programul implementeaza interfata ZileSaptamana definita in sectiunea precedenta si continand constante asociate zilelor saptamanii. Programul citeste de la consola un sir de caractere prin preluarea lui din fluxul de intrare cu metoda readLine care returneaza un String.io declara o serie de metode ce definesc comportamentul unui flux de intrare date independent de platforma implementate de clasa DataInputStream.out.flush(). int. case VINERI: System. final int readLong()throws IOException.

java Datele constante de tip caracter se reprezinta prin incadrarea intre apostroafe a caracterului respectiv: ‘<caracter>’... 3. Un String este un obiect care grupeaza un sir de caractere intr-un ansamblu unitar. Astfel de exemplu ‘A’ reprezinta de fapt valoarea intreaga 65. char charArray[] = new char[10]. Instructiunile: .. 1. Java trateaza toate obiectele String anonime cu acelasi continut ca fiind un singur (acelasi) obiect cu mai multe referinte. ...Compilarea si executia programului Zile. Exista sapte tipuri de constructori pentru obiecte de tip String. .. .....104 CURS 9 Caractere si obiecte de tip String Figura 9. . Instructiunile: . creeaza un obiect String al carui continut este copiat din String-ul referit de s1. s = new String(s1).. String s.. Referinta la acest obiect este atribuita variabilei s.. 2. avand lungimea 0. String s. Instructiunile: . Aici variabila culoare este o referinta la obiecte din clasa String. care nu contine nici un caracter. String culoare = “Rosu”. String s. Acestei variabile i se atribuie o valoare care refera Stringul anonim “Rosu”. De exemplu “(40)01-4100400” (un numar de telefon) este un string constant... Un String constant se reprezinta prin sirul de caractere continut incadrat de ghilimele: “<sir de caractere>”. Un String poate fi atribuit la declarare unei variabile referinta la String: . String-urile constante se mai numesc si obiecte String anonime. O data codificata astfel reprezinta de fapt o valoare intreaga egala cu codul asociat caracterului.. s = new String(charArray). . s = new String().4. Referinta la acest obiect este atribuita variabilei s.s1=”Sursa”. creeaza un String vid.

6. ... String s. creeaza un obiect String al carui continut este copiat din obiectul din clasa StringBuffer referit de buffer... este generata o exceptie StringIndexOutOfBoundsException. .4).5. char charArray[] = new char[10]. . creeaza un obiect String al carui continut este initializat prin preluarea a 4 caractere din tabloul referit de charArray incepand cu deplasamentul 5. Al doilea argument al constructorului (0). 105 creeaza un obiect String al carui continut este preluat din tabloul de caractere referit de charArray.. Referinta la acest obiect este atribuita variabilei s.. .. s = new String(charArray. creeaza un obiect String al carui continut este initializat prin preluarea caracterelor din tabloul referit de charArray. Instructiunile: . char charArray[] = new char[10]. String s. String s.PROGRAMARE IN JAVA .. String s. Instructiunile: . obiectul referit de buffer este un sir de caractere vid. Astfel la creere. s = new String(charArray... In Java caracterele sunt codate pe 2 octeti (Unicode)..5. Referinta la acest obiect este atribuita variabilei s.. Al doilea argument al constructorului (0). . 4.. .. 7. Un obiect StringBuffer este un String care poate fi redimensionat dinamic. . Mascand octetul superior (hibyte=0) codul caracterelor preluate este echivalent codului ASCII. Daca deplasamentul sau numarul de caractere preluate sunt prea mari astfel incat este depasita limita tabloului. buffer. Referinta la acest obiect este atribuita variabilei s.. . Instructiunile: . este octetul de mascare hibyte care se aplica tuturor caracterelor preluate... Instructiunile: . StringBuffer buffer. este generata o exceptie StringIndexOutOfBoundsException... 5.0. buffer = new StringBuffer().0). Obiectul este redimensionat dinamic la adaugarea cu metoda append a caracterelor din String-ul anonim “Sursa”. s = new String(buffer)..4). s = new String(charArray.. Referinta la acest obiect este atribuita variabilei s.Note de curs .Referinta la acest obiect este atribuita variabilei s.append(“Sursa”). de lungime 0.. char charArray[] = new char[10]. creeaza un obiect String al carui continut este initializat prin preluaarea a 4 caractere din tabloul referit de charArray incepand cu deplasamentul 5... numit hibyte reprezinta un octet de mascare a caracterelor preluate din tablou. Daca deplasamentul sau numarul de caractere preluate sunt prea mari astfel incat este depasita limita tabloului.

.. . byteArray [5] 52.4).getChars(3. Spre deosebire de obiectele tablou care contineau o variabila length a carei valoare reprezenta numarul de elemente ale tabloului. s. Ultimul argument al metodei (4) specifica deplasamentul in tablou incepand cu care se vor copia caracterele.(‘3’. este generata o exceptie StringIndexOutOfBoundsException. getChars si getBytes Asa cum s-a aratat mai sus.byteArray. . etc. String s = “0123456789”.’6’. Astfel charArray[4]va contine caracterul ‘3’. I schimb contin metoda length() care returneaza numarul de caractere continute de sir (lungimea sirului). obiectele din clasa String nu contin o astfel de variabila.’7’). String culoare = “Rosu”. String-urile isi cunosc propria lungime. ¾ Similara metodei getChars() este si metoda getBytes() cu deosebirea ca din String sunt copiati numai octetii inferiori ai caracterelor. ..getBytes(3.. .8.. charAt.Daca deplasamentul k este mai mare decat permite lungimea siruluieste generata o exceptie StringIndexOutOfBoundsException..’7’). . s..106 CURS 9 Metodele length.out.. Astfel instructiunile: . String s = “0123456789”.8... Pentru a obtine caracterul de pe pozitia k se foloseste metoda charAt(k)... byte byteArray=new byte[10]. vor afisa la consola: Sirul “Rosu” are lungimea 4 ¾ Elementele sirului continut de un obiect din clasa String sunt indexate de la 0 la n-1 unde n este numarul de caractere din sir.println(“Sirul \”“+culoare+ ”\” incepe cu caracterul “+culoare.. System.charArray. incepand cu pozitia 3 si terminand cu pozitia 8 exclusiv . charArray[5] caracterul ‘4’. etc.’4’. String culoare = “Rosu”. . char charArray=new char[10]. Astfel byteArray [4] va contine 51..’5’.’5’.’4’. Instructiunile urmatoare copiaza din sirul “0123456789” in tabloul byteArray octetii inferiori a 5 caractere. vor afisa la consola: Sirul “Rosu” incepe cu caracterul R ¾ Metoda getChars() permite copierea incepand cu un deplasament dat unui numar specificat de caractere din String.println(“Sirul \”“+culoare+ ”\” are lungimea “+culoare. Astfel instructiunile: ..charAt(0)). Caracterele sunt copiate intr-un tablou de caractere.4). incepand cu pozitia 3 si terminand cu pozitia 8 exclusiv (‘3’. System...Daca deplasamentul sau numarul de caractere preluate sunt prea mari astfel incat este depasita limita String-ului.length()).out. Instructiunile urmatoare copiaza din sirul “0123456789” in tabloul charArray 5 caractere. String-urile sunt obiecte care incapsuleaza alaturi de sirul de caractere continut si metodele de prelucrare specifice ale acestuia: ¾ Ca si tablourile.’6’.

Note de curs 107 Compararea sirurilor de caractere Inainte de a discuta despre compararea String-urilor sa urmarim rezolvarea unei probleme de sortare. t=x[k].out. Observam ca pentru o secventa cu N elemente.3. Comparam primul numar cu al doilea. Deoarece 3 > 2 se interschimba 3 cu 2.2. de aceasta data pentru secventa fara ultimul element care se stie ca este cel mai mare si deci va ramane oricum pe ultima pozitie: Secventa prelucrata este 3. Daca primul numar este mai mare ca cel de al doilea le interschimbam.k.k<N-i-1. int k){ int t.6. Dupa fiecare procesare secventa prelucrata se “scurteaza” cu cate un element.3.i<N-1.2.5.3.3.2.4.4. Se compara x0 cu x1. Aceasta metoda se bazeaza pe urmatorul mecanism: Se porneste de la secventa de N numere pe care dorim sa le ordonam crescator {xk}k=0. Repetand din nou prelucrarea secventei 2.. .i. Aici algoritmul se termina deoarece secventa ramasa 1 contine un singur element.4. } static void print(int[] x){ int N=x. System.1.6.6.1.1. Deoarece 3 < 4 elementele nu se interschimba.1.print("{ "). Se repeta pasii anteriori. Se obtine secventa 3. Se obtine secventa 3. de exemplu 6.1.1. Din nou cel mai mare numar din secventa s-a “ridicat” pe ultima pozitie.4.print(x[i]+" ").6.3.length. Deoarece 4 > 1 se interschimba 4 cu 1.PROGRAMARE IN JAVA .i++) for(k=0.. Implementarea in limbajul Java a algoritmului de sortare prin metoda bulelor este prezentata in continuare.3.1 se obtine 1. Avand dat un tablou de elemente intregi oarecare. Se observa ca cel mai mare numar din secventa s-a deplasat la capatul secventei.1. Se obtine 2. Pentru aceasta trebuie sa folosim un algoritm de sortare.3. secventa ramanand 2. sa ordonam aceste elemente in ordine crescatoare. astfel deoarece 6 > 2. class BubleSort{ static void swap(int[] x. Continuand similar pentru urmatoarele numere pana la penultimul se obtinesecventa: 3. Am obtinut deci in final secventa ordonata crescator 1.4. 3 ia locul lui 6 iar 6 locul lui 3.1.2. x[k]=x[k+1]. Daca al doilea numar este mai mare ca cel de al treilea le interschimbam.4. Se compara al doilea numar cu al treilea. Se obtine 2.2. Astfel deoarece 6 > 3. } static void sort(int[] x){ int N=x.k++) if(x[k]>x[k+1])swap(x. avem N-1 procesari.N-1 .1. 2 ia locul lui 6 iar 6 locul lui 2.4.i++){ System. Repetand aceleasi prelucrari secventei ramase 2.1 (N=5). Un astfel de algoritm este metoda buble-sort.2.. Se compara x2 cu x3.out. Rezultatele compilarii si executiei programului sunt prezentate in figura 9.2. Se compara x1 cu x2.1 se obtine secventa 2. x[k+1]=t. for(i=0.4. for(int i=0. asa cum se ridica spre suprafata o bula intr-un pahar de apa minerala..k).i<N.4.length.

for(int i=0.out. x[k]=x[k+1]. for(int i=0.length. } System.i++){ System. System. for(i=0. } static void sort(char[] x){ int N=x.Compilarea si executia programului BubleSort.i<10.println("Secventa sortata:").out.print("{ "). sort(x). x[k+1]=t.i<N-1.println("Secventa initiala:").out. print(x). sort(x).out.i<10. } static void print(char[] x){ int N=x.out. print(x).108 } System.print(x[i]+" "). CURS 9 } public static void main(String[] arguments){ int x[]=new int [10]. } . System.k).i<N.out.5.out.k++) if(x[k]>x[k+1])swap(x. int k){ char t.i++) for(k=0.k.java Avand in vedere ca datele de tip caracter sunt reprezentate in memorie prin codurile asociate care sunt de fapt numere intregi.println("Secventa sortata:").length. } } Figura 9.i.println("Secventa initiala:"). } public static void main(String[] arguments){ char x[]=new char [10].println("}").i++) x[i]=1+(int)(Math. System. System. print(x).println("}").k<N-i-1. System. putem sa modificam programul de mai sus pentru a sorta secvente de caractere: class CharSort{ static void swap(char[] x. for(int i=0. t=x[k]. print(x).i++) x[i]=(char)(65+(int)(Math.out.random()*10)).random()*10).

. Deci sirul s2 este mai mare decat s1.out. } static void sort(String[] x){ int N=x.print(x[i]+" "). Astfel instructiunile: . Clasa String ofera pentru aceasta operatie metoda compareTo().compareTo(s2)). Folosind metoda compareTo() vom modifica programul anterior pentru a sorta un tablou de siruri de caractere: class StringSort{ static void swap(String[] x.println(s1. for(int i=0.Compilarea si executia programului CharSort.out. x[k]=x[k+1].k).i<N. compararea se face prin diferenta dintre primul caracter diferit a lui s1 si a primului caracter diferit a lui s2.length. Aceasta metoda se bazeaza pe compararea lexicografica a sirurilor. vor afisa la consola: -1 deoarece primele caractere diferite din cele doua siruri sunt ‘1’ cu codul 49 din s1 si ‘2’ cu codul 50 din s2. Diferenta dintre acestea este –1. String s1 = “S1”. for(i=0. } static void print(String[] x){ int N=x.. x[k+1]=t..Note de curs } 109 Figura 9. } .i++) for(k=0. int k){ String t.k<N-i-1.. un numar negativ daca sirul argument cu care se face compararea este “mai mare” decat sirul a carui metoda compareTo() este invocata si un numar pozitiv daca sirul argument este “mai mic”. System.print("{ "). De data aceasta nu putem folosi pentru comparare operatorii relationali pentru ca sirurile de caractere nu sunt scalari.k.out.out.i<N-1.i.println("}").6. Pentru aceasta avem nevoie de a compara doua elemente de tip String ale tabloului.java Acelasi algoritm il putem aplica pentru a sorta un tablou de String-uri (de exemplu o lista de nume) in ordine alfabetica.compareTo(x[k+1])>0)swap(x. Ea intoarce 0 daca sirurile de caractere comparate sunt identice.i++){ System..s2=”S2”. } System.PROGRAMARE IN JAVA .k++) if(x[k]. Deoarece este invocata metoda compareTo() a sirului s1. t=x[k]. System. Aceasta valoare returnata de metoda compareTo() se obtine din diferenta codurilor primelor caractere diferite din cele doua siruri.length.

exit(0). } if(arguments[0].8.println("Secventa initiala:"). } } Figura 9. System.equals("hallo")) System.out.println("Usage: java EqTest <string>").Compilarea si executia programului EqTest.exit(0). print(arguments).out. .7.length != 1){ System.println("Usage: java EqTest <string>").java Pentru compararea sirurilor de caractere cu ignorarea diferentei dintre literele mici si mari clasa String prevede metoda equalsIgnoreCase(): class EqICTest{ public static void main (String[] arguments){ if(arguments.println(arguments[0]+"!= hallo"). System.println(arguments[0]+"== hallo").110 CURS 9 public static void main(String[] arguments){ System. Figura 9.length != 1){ System.java In cazul compararii la egalitate a sirurilor se poate folosi in locul metodei compareTo() metoda equals() mostenita de la superclasa Object a clasei String. Aceasta metoda permite testarea la egalitate a doua obiecte. else System.out. sort(arguments). In programul urmator este testat argumentul de tip String din linia de comanda cu care acesta se lanseaza in executie cu String-ul “hallo”. print(arguments).out.out. } } Rezultatele compilarii si executiei programului sunt prezentate in figura 9. System.out. Metoda intoarce true daca obiectele sunt egale sau false in caz contrar.Compilarea si executia programului StringSort. class EqTest{ public static void main (String[] arguments){ if(arguments.8.println("Secventa sortata:").

. al treilea argument (10) specifica deplasamentului subsirului in sirul s2 iar ultimul.out.regionMatches(7...println(s1. String nume[] = new String[100].equalsIgnoreCase("hallo")) System.i<100.out. } } 111 Rezultatele executiei programului sunt prezentate in figura 9. vor afisa toate sirurile din tabloul nume care se termina cu subsirul “Ionescu”. Primul argument (7) specifica deplasamentului subsirului in sirul s1 a carui metoa regionMatches() este invocata. lungimea subsirurilor comparate.i<100.n) care verifica daca sirul s2 se regaseste in sirul s1 la pozitia n..// initializare tablou for(int i=0. String nume[] = new String[100]. System. Astfel instructiunile: .. String s1 = “Primul sir S1”. instructiunile: .println(arguments[0]+"== hallo"). Astfel instructiunile: . Metoda startsWith() mai are o varianta cu doua argumente: s1..Compilarea si executia programului EqICTest.PROGRAMARE IN JAVA . .i++) if(s1[i].. ...java Pe langa metodele de testare la egalitate discutate mai sus. Figura 9. metoda regionMatches() va returna valoarea true care va fi afisata.3))..i++) if(s1[i].out.println(nume[i]).s2=”Al doilea sir S2”.startsWith(s2. Pentru cazurile in care vrem sa verificam daca sirul incepe/se termina cu o anumita secventa de caractere clasa String prevede metodele startsWith() si endsWith().. . clasa String prevede si o metoda regionMatches() prin care putem testa la egalitate numai portiuni ale sirurilor comparate. Metoda intoarce true daca subsirurile sunt egale si false in caz contrar.println(nume[i]).out..out.endsWith(“Ionescu”)) System.startsWith(“Mihai”)) System.s2..10. vor compara subsirul de 3 caractere cu deplasamentul 7 din sirului s1(“sir”) cu subsirul de 3 caractere cu deplasamentul 10 din sirului s2(“sir”).Note de curs } if(arguments[0]. . (3). vor afisa toate sirurile din tabloul nume care incep cu subsirul “Mihai”..9.9. Intrucat cele doua subsiruri sunt egale.. Al doilea argument (s2) indica sirul cu care se face comparatia. Similar. else System.println(arguments[0]+"!= hallo").// initializare tablou for(int i=0. ...

getText()).getText()). resize(300. out. in2.s2. in1.*. private TextField in1=new TextField().handleEvent(e). out.setText(""). setLayout(new GridLayout(5.setText(s1+" / "+s2+" = "+String.target==in2){ p=Integer. l2=new Label("Introduceti impartitorul"+ " si apasati tasta ENTER").PROGRAMARE IN JAVA .add(in1).setEditable(false).add(in2). } return super.awt. add(out). return true. } public boolean handleEvent(Event e){ if(e.valueOf(p/q)).1)). out=new TextField().parseInt(s2=in2. System.150). dispose(). if(e. Sa analizam urmatorul exemplu: import java.exit(0).Note de curs 169 Curs 14 Exceptii In timpul executiei unui program pot sa apara situatii exceptionale care sa duca la oprirea programului sau la obtinerea unor rezultate eronate. De asemenea este creat un camp de editare “read . class Divizor extends Frame{ private Label l1=new Label("Introduceti deimpartitul").q.setText(""). } return true.Object o){ String s1. in2=new TextField().id==Event. q=Integer. public Divizor(){ super("Test impartire"). add(l2). } public boolean action(Event e. add(l1). show().WINDOW_DESTROY){ hide(). private int p.parseInt(s1=in1. } public static void main(String[] arg){ Divizor f=new Divizor(). } } programul va crea doua campuri de editare in1 si in2 care vor servi pentru introducerea a doua stringuri de intrare s1 si s2 ce vor fi convertite in numere intregi si stocate in variabilele intergi p si q.

pentru afisarea rezultatelor. Totusi aparent in fereastra aplicatiei nu se intampla nimic. apelata de metoda java. Aceasta lista de apeluri succesive (stiva de apeluri) faciliteaza localizarea erorii aparute la executia programului.class Ce se va intampla insa daca se introduc ca date de intrare valorile 4 si 0.lang. indicand precis instructiunea care nu a functionat corect.Component..s2. datele introduse fiind pur si simplu ignorate.awt.Object o){ String s1. apelata de.14. q=Integer. Dupa terminarea introducerii datelor.2 Mesajul aparut la consola in cazul impartirii prin 0 Acest mesaj ma avertizeaza asupra exceptiei aparute.setText(""). procesorul ar fi generat o intrerupere interna numita exceptie tratata de sistemul de operare. In schimb la consola apare afisat mesajul din figura 14. Daca programul ar fi incercat sa efectueze impartirea.getText()).q)). Explicatia acestui mesaj si a faptului ca programul nu s-a blocat si continue sa lucreze normal in continuare consta in detectarea exceptiei inainte ca ea sa se produca de fapt si sa cauzeze o eroare fatala de sistem.1 Fereastra afisata de programul Divizor.target==in2){ p=Integer. Clasele proiectate de noi pot si ele sa realizeze detectarea si tratarea exceptiilor aparute in timpul executiei programului.impartire prin zero . out.handleEvent in linia 29 din fisierul p14_1.170 CURS 14 only”.setText(s1+" / "+s2+" = "+div(p.java.action. cauza .si indica sursa acesteia – exceptia a aparut la executia instructiunii din linia 38 a programului din fisierul p14_1. out. continutul campurilor in1 si in2 este sters iar i campul out va fi afisat un string continand rezultatul impartirii p/q. De exemplu dupa introducerea valorilor 4 si 2 in campurile in1 si in2 fereastra afisata de program este cea din figura 14. in metoda Divizor.getText()). Fig.ArithmeticException.handleEvent in fisierul Component.parseInt(s1=in1. apelata de metoda Divizor.java.14. if(e. in2.setText("").1. . Fig. in final. Daca dorim ca programul anterior sa evite generarea unei exceptii si sa semnaleze utilizatorului printr-un mesaj ca datele introduse sunt eronate am putea sa facem urmatoarea modificare in metoda action(): public boolean action(Event e..2. etc. in1. categoria acesteia (java.parseInt(s2=in2.java linia 908.

class si intamplator fisierul Y. parametri de tip eronat la apelul unei metode. Si generarea acestei exceptii poate fi evitata prin verificarea existentei fisierului respectiv pe disc inainte de a apela la metodele lui. Mecanismul de tratare a exceptiilor in Java .int y) apelata pentru efectuarea impartirii celor doua argumente face si validarea datelor afisand mesajul corespunzator: private String div(int x. Incercarea de a preantampina toate exceptiile in aceasta maniera (prin prevederea unor secvente de validare chiar in locul unde ar putea apare erorile) duce la un cod sursa “poluat” de diferite teste de validare devenind foarte greu de inteles si de modificat. } 171 Metoda div(int x. else rezultat= x<0? ”Eroare: Infinit negativ”: ”Eroare: Infinit pozitiv”.3 Fereastra afisata de programul Divizor. inexistenta unei clase sau a unei metode. int y){ String rezultat=””. La terminarea executiei acestei rutine controlul este redat programului intrerupt reluandu-se executia acestuia). if(y==0) if(x==0) rezultat= “Rezultat nedefinit”. metoda care a provocat exceptia este oprita si se executa secventa de cod care trateaza exceptia de tipul respectiv. return rezultat. Realizatorii limbajului Java au ales pentru tratarea exceptiilor mecanismul similar celui descris in standardul ANSI pentru tratarea exceptiilor in limbajul C++.class Exista multe alte tipuri de exceptii ce pot apare.PROGRAMARE IN JAVA .3. depasire aritmetica (valoarea rezultata este prea mare pentru tipul respectiv de data). etc. In cazul exceptiilor. Acest mecanism prevede tratarea separata a exceptiilor – in afara codului principal. } Mesajele afisate de in fereastra aplicatiei la introducerea unei valori nule pentru divizor sunt redate in figura 14. se genereaza o exceptie ClassNotFoundException. in care aceste exceptii pot apare.class apeleaza o metoda a altei clase Y. mecanismul fiind asemanator cu cel de tratarea intreruperilor intr-un sistem de operare (executia programului este oprita si se executa o rutina de tratare a intreruperii respective. Fig. Codul de tratare a exceptiilor este executat numai in momentul in care apare exceptia. Iata cateva dintre acestea: depasirea limitelor unui tablou (index prea mare). insuficienta memorie pentru alocare la instantierea unui obiect.14. index negativ.class a fost sters de pe disc. De exemplu daca o metoda a unei clase X.Note de curs } return true.

Ultimul bloc catch poate fi urmat de un bloc optional finally continand o secventa de instructiuni care este executata intotdeauna. pentru a exemplifica cele prezentate mai sus sa rescriem programul anterior folosind try. daca exista posibilitatea ca la executia unei metode a clasei sa apara o eroare. In momentul in care s-a produs exceptia. Daca aceasta metoda nu prevede o procedura de tratare a exceptiei respective. etc. blocul in care s-a produs exceptia expira. throw si catch pentru a detecta. Exceptia “aruncata” este un obiect continand informatii privind tipul erorii produse si alte date semnificative pentru recuperarea acesteia. Instructiunea care a generat exceptia se numeste punctul de “aruncare” al exceptiei. daca o astfel de procedura exista. Astfel revenirea in lantul apelurilor are loc pana la metoda care prevede handler-ul de tratare a exceptiei respective. a mai multor exceptii inrudite sau numai a unei anume exceptii. In mod normal exceptia produsa intr-o metoda va fi tratata in metoda apelanta. Un program poate sa ignore aparitia exceptiilor dar aceasta poate avea un efect devastator in cazul aplicatiilor comerciale sau critice. In acest stadiu nu exista garantia ca in afara metodei exista un handler al exceptiei – o secventa de cod care sa trateze aceasta exceptie daca ea va fi generata. Exceptiile pe care le poate arunca o metoda se specifica prin clauza throws (arunca). din momentul in care s-a produs “aruncarea”. exceptia “aruncata” de metoda va fi “prinsa” si tratata. Tratarea exceptiilor in Java La proiectarea unei clase. in cazul unor aplicatii pentru uz personal este uzual ca multe erori sa fie ignorate sau sa fie tratate prin terminarea executiei programului pentru a evita obtinerea unor rezultate eronate. Acest mecanism permite “prinderea” tuturor exceptiilor posibile. Acest bloc este locul ideal in care sa se realizeze eliberarea resurselor alocate in timpul executiei. aceasta metoda poate fi prevazuta cu proprietatea de a “arunca” (genera) o exceptie. revenindu-se la metoda apelanta in procedura de tratare a exceptiei. Fiecare bloc catch specifica un tip de exceptie si handler-ul acesteia adica secventa de instructiuni pentru tratarea acestei exceptii. indiferent daca survine sau nu o exceptie. permitand ca executia programului sa poata fi continuata. exceptia urmand a fi tratata de handlerul metodei apelante a metodei apelante. si aceasta metoda va fi terminata. revenindu-se fortat la metoda care a apelat metoda apelanta a metodei care a provocat exceptia. daca la executia blocului try nu este generata nici o exceptie. O astfel de abordare nu este insa acceptabila in cazul aplicatiilor critice care vor necesita o procesare corespunzatoare a exceptiei asigurandu-se executia in continuare a programului in conditii de siguranta.172 CURS 14 permite unui program sa “prinda” (sa detecteze) o exceptie produsa intr-o sectiune a sa si sa o proceseze prin executia unei proceduri de recuperare numita exception handler. Daca dupa ultimul bloc catch urmeaza un bloc finally se executa secventa de instructiuni din acest bloc (indiferent daca s-a “aruncat” o exceptie sau nu). Cand o exceptie este “aruncata” executia blocului try este abandonata si se cedeaza controlul blocului catch corespunzator tipului respectiv de exceptie. metoda este terminata fortat. programul nu va mai relua executia din acest punct dupa recuperarea erorii. reducand probabilitatea aparitiei unor erori fatale la executia programului fara ca aceasta sa fie detectata si tratata corespunzator astfel incat sa se asigure recuperarea erorii. Exceptia este “aruncata” din interiorul unui bloc try din corpul metodei. executia esete continuata cu instructiunea imediat urmatoare ultimului bloc catch. Aceasta permite realizarea unor programe robuste. Secventa de program care se banuieste ca poate “arunca” o exceptie este incadrata intr-un bloc try (incearca) urmat imediat de unul sau mai multe blocuri catch (prinde). Spre deosebire de tratarea intreruperilor. indica si procesa .

setText(s1+" / "+s2+" = "+ div(p.valueOf(x/y). int y) throws ArithmeticException { if(y==0) throw new ArithmeticException().target==in2){ p=Integer.q)).Note de curs 173 exceptia “impartire prin 0”. } catch(ArithmeticException exception) {//Prinderea exceptiei out.lang avem definite urmatoarele clase de exceptii : Exception ClassNotFoundException CloneNotSupportedException IllegalAccessException InstantiationException InterruptedException NoSuchMethodException RunTimeException ArithmeticException ArrayStoreException ClassCastException IllegalArgumentException IllegalThreadStateException NumberFormatException IllegalMonitorStateException IndexOutOfBoundsException ArrayIndexOutOfBoundsException StringIndexOutOfBoundsException NegativeArraySizeException NullPointerException SecurityException Dintre acestea vom alege clasa ArithmeticException care corespunde cel mai bine tipului de eroare ce dorim sa-l tratam in aplicatia noastra (vezi si mesajul afisat la consola – fig.parseInt(s1=in1.setText(""). in1. Modificarile aduse programului anterior vor afecta doar metodele action() si div(): public boolean action(Event e.toString()).Object o){ String s1. q=Integer.//Aruncarea exceptiei return String.PROGRAMARE IN JAVA .setText(exception.parseInt(s2=in2. } } return true. In pachetul java. Pentru inceput vom cauta o clasa Exception care corespunde tipului nostru de exceptie. } .14.getText()). try{// Detectia exceptiei out. in2. } private String div(int x.getText()).s2.2). if(e.setText("").

valueOf(x/y). Dupa introducerea valorilor 5 si 0 in campurile in1 si in2 fereastra afisata de program este cea din figura 14.4. Fig.2. se creaza un obiect din clasa ArithmeticException care este “aruncat” cu instructiunea : throw new ArithmeticException(). return String.5. Exceptia este detectata in blocul try din metoda action() si “prinsa” de blocul catch care va afisa stringul ce caracterizeaza exceptia exact acelasi ca si in figura 14. else if(x<0) throw new ArithmeticException( ”Eroare: Infinit negativ”): else throw new ArithmeticException( ”Eroare: Infinit pozitiv”). } .174 CURS 14 Metoda div() a fost prevazuta cu clauza throws ArithmeticException permitandu-i astfel sa “arunce” exceptii din aceasta clasa.valueOf(x/y). int y) throws ArithmeticException { if(y==0) throw new ArithmeticException(“Impartire prin 0”). In cadrul acestei metode daca argumentul y este nul.class Acum putem modificand metoda div() sa semnalam prin mesaje diferite si un rezultat Infinit negativ.class Programul a afisat in campul out mesajul standard corespunzator acestei exceptii. De data aceasta in fereastra consola nu va mai aparea nici un mesaj deoarece exceptia a fost prinsa si tratata de clasa definita de noi. } Fereastra afisata de program in acest caz este cea din figura 14.5 Fereastra afisata de programul Divizor. return String. Folosind acest constructor in metoda div() : private String div(int x.4 Fereastra afisata de programul Divizor. Constructorul clasei ArithmeticException(String msg) permite setarea stringului ce caracterizeaza exceptia.14. Fig. nedeterminat sau Infinit pozitiv dupa valorile deimpartitului: private String div(int x.14. int y) throws ArithmeticException { if(y==0) if(x==0) throw new ArithmeticException( “Rezultat nedefinit”).

odata ce obiectul a fost aruncat.PROGRAMARE IN JAVA . return String.14. Fig.14.7 Fereastra afisata de programul Divizor.Note de curs 175 Mesajele afisate de program in acest caz pentru cele trei situatii pentru care sunt “aruncate” de catre metoda div() exceptii din clasa ArithmeticException sunt cele din figura 14. } private String div(int x.Object o){ .} } Modificand corespunzator blocul catch al metodei action() si metoda div() : public boolean action(Event e.. destinat procesarii obiectului aruncat.6 Fereastra afisata de programul Divizor. int y) throws DivByZeroException { if(y==0) throw new DivByZeroException(). revenirea din metoda care a efectuat aruncarea (sau din lantul de apeluri) nu se mai face. class DivByZeroException extends ArithmeticException{ public DivByZeroException(){ super(“Impartire prin 0”).6. blocul try este si el terminat fortat. controlul cedandu-se blocului catch corespunzator.valueOf(x/y)..class Putem de asemenea sa cream propria noastra clasa derivata din clasa ArithmeticException.. } mesajul afisat in campul out la tratarea acestei exceptii va fi cel din figura 14.toString()).. Astfel daca modificam metoda div() ca aceasta sa apeleze la randul sau o metoda validare() in cadrul careia sa se efectueze aruncarea : .setText(exception. catch(DivByZeroException exception) {//Prinderea exceptiei out. } .class Operatorul throw “arunca” un obiect din clasa Trowable sau dintr-o clasa derivata din aceasta cum ar fi clasa Exception sau clasa ArithmeticException derivata din clasa Exception.7: Fig.

in2. setLayout(new GridLayout(5. show(). add(l1). out. Blocul try va fi terminat si el.1)). private TextField in1=new TextField(). System. out=new TextField().setText("").valueOf(x/y).parseInt(s2=in2. blocul try in care sa-a initiat apelul inlantuit devine expirat si se executa blocul catch corespunzator exceptiei.WINDOW_DESTROY){ hide().handleEvent(e). in2=new TextField().getText()).q.setEditable(false). exceptiile pot fi aruncate de exemplu de constructorii diferitelor obiecte instantiate in cadrul blocului. } private void validare(int y) throws DivByZeroException { if(y==0) throw new DivByZeroException().176 CURS 14 private String div(int x. import java.parseInt(s1=in1.150).id==Event. el totusi va detecta toate exceptiile care pot aparea la executia instructiunilor ce il compun. va detecta si trata exceptia aritmetica “impartire prin zero” aruncata chiar de sistem afisand acelasi mesaj ca si cel din figura 14. dispose(). In baza acestui mecanism. q=Integer.exit(0).add(in1).awt. in1. Acest lucru este valabil si pentru un lant de apeluri oricat de lung. Toate metodele din lant vor fi abandonate. . int y) { validare(y) return String.add(in2). } public boolean handleEvent(Event e){ if(e. } return super.target==in2){ p=Integer. if(e.} la aruncarea exceptiei.*. public Divizor(){ super("Test impartire").getText()). class Divizor extends Frame{ private Label l1=new Label("Introduceti deimpartitul"). Astfel de exemplu programul de mai jos desi nu mai contine metoda div() care sa o arunce. add(out). return true. } public boolean action(Event e.4.Object o){ String s1. resize(300. private int p. add(l2). chiar daca aparent nu apare o instructiune throw. l2=new Label("Introduceti impartitorul"+ " si apasati tasta ENTER").setText(""). se va revenirea din lantul de apeluri div()->validare() direct in blocul catch(DivByZeroException exception) care contine handlerul exceptiei DivByZeroException.s2.

setText(exception.setText(exception. Striva de apeluri poate fi afisata prin apelul printStackTrace() definita in clasa Thowable si mostenita de toate clasele derivate. } catch(ArithmeticException exception) {//Prinderea exceptiei out.valueOf(p/q)).14. o aplicatie fara interfata grafica este terminata iar una prevazuta cu interfata grafica isi va continua executia asteptand si prelucrand noi evenimente. } } Lantul de apeluri din care se face “aruncarea” fiind similar cu cel din figura 14..toString()).PROGRAMARE IN JAVA . De exemplu catch(ArithmeticException e) va prinde si exceptiile din clasa definita de noi DivByZeroException iar catch(Exception e) va prinde toate tipurile de exceptii deoarece acestea sunt toate subclase ale clasei Exception. } public static void main(String[] arg){ Divizor f=new Divizor(). La distrugerea acestor obiecte si colectarea lor de catre garbage colector sunt apelate metodele finalize() ale acestora.2.setText(s1+" / "+s2+" = "+String. Utilizarea acestor metode poate fi exemplificata modificand ca mai jos blocul catch din exemplul anterior: . catch(ArithmeticException exception) {//Prinderea exceptiei out. Vom obtine la generarea unei exceptii aritmetice mesajele de la consola si din fereastra aplicatiei prezentate in figura 14. } . exception.8 Fig.. } } return true.8 Utilizarea metodelor getMessage() si printStackTrace() Blocul catch va “prinde” nu numai exceptiile din clasa specificata ca argument ci si toate exceptiile din subclase ale acesteia. Daca pentru o exceptie nu este gasit un handler.Note de curs 177 // Detectia exceptiei try{ out.printStackTrace()..getMessage ()). . De asemenea poate fi utila si metoda getMessage() care intoarce un String continand mesajul setat la instantierea obiectului. dupa afisarea mesajelor corespunzatoare la consola. Toate variabilele si obiectele locale blocului try sunt distruse la aparitia unei exceptii deoarece blocul expira in momentul in care exceptia este prinsa si tratata de blocul catch..

de ce nu ar putea plantatorul nostru sa foloseasca pentru “plantarea” punctelor pe ecran un lucrator care sa efectueze munca.").lucreaza(). } public static void main(String[] argv){ Plantator p=new Plantator(80).} private void planteaza(){ for(int i=0. p.out.i++).i<nrP.flush(). } public void lucreaza(){ for(int i=0.} private void planteaza(){ for(int i=0.lucreaza()."). } } Daca insa plantatorul nostru ar dori sa puna la munca doi lucratori impartind munca intre ei: class Plantator{ public static void main(String[] argv){ Lucrator l1=new Lucrator(40). // temporizare pe durata // plantarii unui punct System.i++) planteaza(). } } class Lucrator{ private int nrP. Programul va fi urmatorul: class Plantator{ private int nrP.out. atunci programele elaborate de noi pina in prezent corespund activitatii unei intreprinderi cu un singur lucrator. } } Continuand paralela.178 CURS 14 Multithreading Daca incercam sa privim procesarea datelor de catre o aplicatie ca pe o activitate similara unei activitati productive. . l.flush().print(".out. l2. Sa consideram urmatorul exemplu. public Plantator(int n){nrP=n. System. l1. Aplicatia noastra trebuie sa “planteze” 80 de puncte pe ecran. Programul ar arata astfel: class Plantator{ public static void main(String[] argv){ Lucrator l=new Lucrator(80). l2=new Lucrator(40).i<100000. public Lucrator(int n){nrP=n.i++). // temporizare pe durata // plantarii unui punct System.out.i++) planteaza().print(".i<100000.i<nrP. } private void lucreaza(){ for(int i=0.lucreaza(). System. Acest lucrator este si patron si executant.lucreaza().

"*"). } Metoda run() joaca rolul metodei main() din aplicatiile cu un singur fir de executie (thread) cum au fost cele prezentate de noi pana in prezent. executandu-se instructiunea l1. incepe sa fie executata metoda run().9 .out. Cand se lanseaza un nou fir de executie. Intai ar lucra l1."). l1.i<nrP. String s){nrP=n.l2. Lansarea firului de executie se face cu metoda start() definita in clasa Thread. } public void lucreaza(){ for(int i=0. Ea este definita ca implementand interfata Runable: class Thread implements Runable Interfata Runable defineste o singura metoda – metoda run(): interface Runable{ void run(). public Lucrator(int n. } } class Lucrator extends Thread{ private int nrP. l2=new Lucrator(40. daca ea este supradefinita intr-o subclasa. De data aceasta ( ca sa punem in evidenta activitatea paralela a celor doi lucratori) unul va “planta” puncte iar celalalt stelute. Altfel ar sta treaba daca cei doi lucratori ar lucra in acelasi timp. System.} private void planteaza(){ for(int i=0.sP=s.".flush().start().i++) planteaza().Note de curs } } 179 O stfel de diviziunea muncii nu ar avea sens deoarece cele doua obiecte Lucrator l1 si l2 nu ar lucra simultan. Aceasta clasa implementeaza un “fir de executie” paralela.print(sP). in paralel.PROGRAMARE IN JAVA . Din aceasta metoda. Aceasta creaza firul de executie si apeleaza metoda run() a acestuia.lucreaza().start().out. private String sP.i++).} } Programul va afisa 80 de caractere alternand puncte cu stelute ceea ce demonstreaza ca cei doi “lucratori” isi desfasoara activitatea in paralel cum se vede si din figura 14. Aceasta se executa in paralel cu celalalte fire de executie (cum ar fi cel care executa metoda main()). // temporizare pe durata // plantarii unui punct System. Acest lucru devine posibil daca definim clasa Lucrator ca fiind subclasa a clasei Thread. Vom modifica programul anterior astfel incat sa fie folositi doi lucratori.i<100000. } public void run(){lucreaza().lucreaza() si abia dupa ce s-ar termina activitatea acestuia s-ar executa si instructiunea l2. Programul este urmatorul: class Plantator{ public static void main(String[] argv){ Lucrator l1=new Lucrator(40. pot fi apelate celalalte metode ale clasei.

} private void planteaza(){ for(int i=0.start().out. ready=true. in care s-au creat si pornit cele doua thread-uri) plus garbage collector-ul care lucreaza in background. se termina si aplicatia. Daca am micsora “durata plantarii” – temporizarea introdusa prin ciclul for in metoda planteaza() – atunci pana sa apuce cel de al doilea thread lucrator sa preia controlul procesorului si sa inceapa sa planteze stelute.ready=false. } public boolean isReady(){return ready. Starea acestui indicator poate fi aflata de “plantator” prin apelul metodei publice isReady().9 Rezultatele afisate de aplicatia Plantator.class Analizand aceste rezultate se pot face doua observatii.i<100000. Firul de executie principal. le opreste din activitate apeland metoda stop(). desi amandoi lucratorii lucreaza cu aceeasi viteza. l2=new Lucrator(40.14. Pentru a termina programul.l2.start(). Existand un singur procesor.180 CURS 14 Fig. cele doua thread-uri trebuiesc oprite."). System.i++) planteaza(). // temporizare pe durata // plantarii unui punct System.out. Pentru ca Plantatorul sa stie cand sa opreasca pe cei doi lucratori vom completa codul clasei Lucrator cu un indicator boolean privat ready care este trecut in starea true cand lucratorul – instanta a clasei Lucrator .stop(). A doua observatie se refera la faptul ca desi cei doi lucratori si-au terminat de plantat punctele si stelutele programul nu s-a terminat ramanand blocat. } } class Lucrator extends Thread{ private int nrP.flush().isReady())). Stelutele si punctele nu alterneaza uniform. public Lucrator(int n. un punct o steluta. private boolean ready. acesta este partajat intre cele doua fire de executie ( plus firul de executie principal. while(!(l1. Aceasta se explica prin faptul ca executia threadurilor este de fapt nu paralela ci cvasiparalela. l1.i<nrP.} public void run(){lucreaza(). primul thread deja si-ar fi terminat treaba plantand pe ecran 40 de puncte la rand.i++).". Plantatorul va testa periodic (intr-un ciclu while) daca cei doi lucratori si-au terminat treaba si daca da.print(sP). String s){nrP=n.l2.stop().isReady()&&l2.sP=s. Abia acum poate si firul principal de executie sa se termine Odata toate firele de executie terminate. private String sP.} } . Prima priveste executia paralela a celor doua thread-uri."*").// Gata munca? l1.si-a terminat munca. Fiecaruia din aceste fire de executie i se cedeaza controlul procesorului pentru o anumita cuanta de timp. Cu aceste modificari programul devine: class Plantator{ public static void main(String[] argv){ Lucrator l1=new Lucrator(40. } public void lucreaza(){ for(int i=0.

el trece in starea Ready.PROGRAMARE IN JAVA . El ramane in aceasta stare pana la apelul de catre alt thread a metodei start().1 – Ciclul de viata al unui thread In aceast graf s-au reprezentat starile.15. va activa toate threadurile din coada. . eventual alaturi de alte threaduri. tranzitiile posibile intre stari si conditiile in care aceste tranzitii au loc. Astfel distingem urmatoarele stari: ¾ Born – thread-ul a fost creat. Starea “semaforului” s este supravegheata de un thread dedicat care in momentul in care “semaforul” ajunge in starea necesara (are culoarea verde) va activa primul thread din coada de asteptare apeland metoda notify() sau apeland metoda notifyAll(). ¾ Ready – threadul este gata pentru executie. intr-o coada de asteptare. asteptand sa ii vina randul sa preia controlul procesorului. In momentul in care un trhread aflat in starea Waiting este astfel notificat.1 Fig. este dezactivat fiind amplasat . asteptand sa i se cedeze controlul procesorului pe durata unei cuante de timp ¾ Running – threadul a preluat controlul procesorului si se executa pe durata unei cuante de timp ¾ Waiting – la fel ca si un automobil care se opreste in coada unui sir de masini asteptand la un semafor culoarea verde pentru a porni mai departe. in urma unei instructiuni wait(s) threadul.Note de curs 181 Curs 15 Ciclul de viata al unui fir de executie Un obiect din clasa Thread din momentul instantierii sale pana la oprirea si distrugerea sa se poate afla in diferite stari reprezentate in figura 15.

activitatea sa incetand definitiv... or itmust be declared in the throws clause of this method. Aceasta metoda primeste ca argument durata in milisecunde a suspendarii activitatii treadului Lucrator. ¾ Dead – threadul trece in aceasta stare cand metoda sa run() se termina sau in urma apelarii metodei sale stop() prin care este “omorat”. int ns) throws InterruptedException unde ms reprezinta durata in milisecunde iar ns o temporizare suplementara de precizie exprimata in nanosecunde. threadul este trecut automat in starea Ready.lang. . Apelul la aceasta metoda va trece threadul Lucrator respectiv in starea Sleeping pe durata specificata.. Metoda stop() trimite threadului un obiect din clasa ThreadDeath – o subclasa a clasei Error. activitatea threadului este blocata pana cand operatia de I/O este efectuata. Metoda este definita in clasa Thread astfel: ¾ static void sleep(long ms) throws InterruptedException ¾ static void sleep(long ms.print(sP). ¾ Suspended . El poate fi reactivat numai de catre un alt thred care va apela metoda resume(). In primul caz codul metodei planteaza() va fi .out.. De exemplu daca threadul prea un caracter dintr-un stream.lang.out.182 CURS 15 ¾ Sleeping .in urma unei instructiuni suspend() threadul este dezactivat pe o perioada nedeterminata de timp. Ca exemplu. Acest lucru rezulta si din definitia data mai sus a metodei. // temporizare 0.. vom folosi metoda sleep() pentru a realiza temporizarea operatiei de “plantare” a unui punct din programul anterior. moment in care trece in starea Ready. activitatea sa va fi blocata pana cand caracterul nu este disponibil in stream si nu este citit cand threadul este trecut in starea Ready. private void planteaza(){ sleep(500).5s pe durata // plantarii unui punct System. Incercand sa compilam programul astfel modificat. exceptia trebuie fie detectata si prinsa in cadrul acestei metode fie sa fie “aruncata” mai departe pentru a fi tratata in afara. Dupa ce timpul T s-a scurs.java(17): Exception java.in urma unei instructiuni sleep(T) threadul este dezactivat pe o perioada de timp T.InterruptedException.InterruptedException must be caugth. va fi semnalata eroarea: p15_1. ¾ Blocked – Pe timpul unei operatii de I/O. realizandu-se astfel temporizarea dorita a operatiei. Vom modifica metoda planteaza() a acestuia inlocuind ciclul de temporizare cu un apel la metoda sleep().flush(). System. Deoarece metoda sleep() este apelata in metoda planteaza(). unde se specifica prin clauza throws ca aceasta “arunca” o astfel de exceptie. private void planteaza(){ try{ .. sleep(500) ^ 1 error Aceasta ne spune ca la executia metodei sleep() poate sa fie generata o exceptie din clasa java. } .

aceasta va trebui sa fie prinsa in metoda run(). Planificatorul amplaseaza threadurile aflate in stare Ready in zece liste circulare. pe aceleasi considerente.2.class Gestionarea threadurilor (comutari.Rezultatul executiei programului Plantator. } . va fi executat pana la terminare threadul C de pe nivelul 9.out. Waiting. In acest caz. Vor urma threadurile D. este amplasat de Planificator in lista corespunzatoare nivelului sau de prioritate. Suspended sau Blocked) dupa ce threadul curent de prioritate inferioara este trecut in starea Ready ( dupa expirarea cuantei de timp alocate sau apelarea metodei yield()) controlul este cedat threadului nou aparut.flush().5s pe durata // plantarii unui punct 183 } catch(InterruptedException exception){}//daca apare exceptia. La un moment dat numai un singur thread se poate afla in starea Running. sa analizam de exemplu cazul din figura 15. el trece in starea Ready si planificatorul il amplaseaza in lista corespunzatoare nivelului sau de prioritate dupa care trebuie sa aleaga un nou thread pe care sa-l treaca in starea Running. adica in metoda planteaza(). Acesta se numeste threadul curent.2 .) intra in sarcina unui thread planificator care se executa cu prioritate maxima. fiecare dintre acestea avand asociat un nivel de prioritate. Daca si pentru aceasta metoda vom specifica prin clauza throws sa “arunce” exceptia. etc.. A doua varianta nu este posibila deoarece daca metoda planteaza() va arunca exceptia. Metoda run() nu poate sa arunce aceasta exceptie mai departe deoarece in acest caz nu va mai corespunde cu interfata Runable si deci nu va mai supradefini metoda run() a clasei Thread. Deci odata si odata tot va trebui undeva sa prindem si sa tratam exceptia si cel mai bine este sa o facem acolo unde ea poate fi detectata prima data.PROGRAMARE IN JAVA . vor fi executate pana la terminare. va alege din lista cu threadurile cu prioritatea 8. //nu se face nimic System.Note de curs sleep(500).out. El alege acest thread din lista cu prioritatea maxima 10. un thread cu prioritate mai mare este introdus in lista de threaduri Ready (in urma unei tranzitii din starile Born. de prioritate mai mare. System. Threadul care a junge in starea Ready. trebuie “prinsa” in metoda lucreaza() care apeleaza metoda planteaza(). Dupa ce lista de threaduri Ready de pe nivelul de prioritate 10 va fi vida. Rezultatul afisat la consola de programul astfel modificat este prezentat in figura 15. Fiecare thread are la randul sau specificat un nivel de prioritate (o valoare intreaga cuprinsa intre 1 si 10). // temporizare 0.15. primind succesiv cate o cuanta de timp controlul procesorului. etc. Dac la un moment dat..print(sP). Daca aceasta lista nu contine nici un thread va cauta in lista cu prioritatea imediat urmatoare 9. treceri dintr-o stare in alta. Niveluri de prioritate a firelor de executie Fig.3. E . Sleeping. threadurile A si B cu nivelul de prioritate 10. Daca si aceasta lista este vida. aceasta. inaintea oricarui alt thread aflat in starea Ready. In momentul in care threadului curent ii expira cuanta de timp alocata sau executa metoda yield(). Pentru a ne clarifica consecintele unei astfel de planificari a executiei threadurilor.

lang.NORM_PRIORITY = 5. ¾ Thread. Prioritatea threadului este stabilita la instantiere ca fiind egala cu prioritatea threadului parinte.10]. Fig. Astfel prioritatea threadurilor l1 si l2 din exemplul nostru va fi egala cu prioritatea threadului principal care le-a creat (in cadrul metodei main()).MAX_PRIORITY=10.15. dupa terminarea threadului G de pe nivelul 6 si a threadurilor H si I de pe nivelul 5. threadurile J si K vor fi executate ultimele. Clasa Thread defineste trei constante corespunzand valorilor uzuale ale nivelurilor de prioritate: ¾ Thread. deoarece au nivelul de prioritate cel mai mic (1).IllegalArgumentException daca argumentul are o valoare in afara domeniului admis [1.3 Planificarea pe niveluri de prioritate a executiei threadurilor Prioritatea threadurilor poate fi obtinuta prin apelul metodei getPriority() si modificata cu metoda setPriority() care “arunca” o exceptie din clasa java.MIN_PRIORITY = 1.184 CURS 15 si F avand nivelul de prioritate 7 deoarece lista de pe nivelul 8 este vida. ¾ Thread. .

} } .isReady()&&l3. etc. class Plantator{ public static void main(String[] argv){ Lucrator l1=new Lucrator(). l4=new Lucrator().out. private int sleepTime. } } class Lucrator extends Thread{ private boolean ready.isRe ady())).l2.l4.println(getName()).start().start().random()*5000). } System.l3.stop().err.Note de curs 185 Unele metode ale clasei Thread ¾ Threadul construit cu constructorul Thread() capata implicit numele “Thread-” + n unde n este numarul de ordine al threadului (Thread-1 daca este primul.l3.start(). ready=true.toString()). l1.isReady()&&l4.println("Exception"+ e. System.l2. while(!(l1. public Lucrator(){ sleepTime=(int)(Math. Thread-2 daca este al doilea. ¾ Numele este afisat apeland metoda getName() care intoarce un String continanad numele threadului.} // executia threadului public void run(){ try{ sleep(500).PROGRAMARE IN JAVA . l1.stop().) Programul urmator creaza patru threaduri care dupa o temporizare aleatoare isi afiseaza numele si se termina. } catch(InterruptedException e){ System.stop(). l3=new Lucrator().stop().isReady()&&l2. l2=new Lucrator().out.println(getName()+":"+sleepTime).start(). } public boolean isReady(){return ready.l4.

l2=new Lucrator(“Diego”).l3.l3. l4=new Lucrator(“Izaura”).out.stop().4 Fig. Unul dintre acestia este Thread(String nume). Acest constructor permite atribuirea threadului creat a unui nume specificat ca parametru. while(!(l1.15. Vom modifica programul anterior pentru a folosi acest constructor: class Plantator{ public static void main(String[] argv){ Lucrator l1=new Lucrator(“Hose”).isRe ady())). sleepTime=(int)(Math. } } class Lucrator extends Thread{ private boolean ready.l4.l4. public Lucrator(String nume){ super(nume).random()*5000).isReady()&&l4.l2.start().} // executia threadului .start(). clasa Thread mai prevede si alti constructori. } public boolean isReady(){return ready.isReady()&&l3. l1. l3=new Lucrator(“KuntaKinte”). private int sleepTime.stop().class Pe langa constructorul Therad() folosit de noi in exemplul precedent.start().l2.186 CURS 15 Rezultatele afisate de program in trei executii succesive sunt redate in figura 15.Rezultatul executiei programului Plantator.stop().isReady()&&l2. System.println(getName()+":"+sleepTime).4 . l1.start().stop().

Din aceasta stare. threadul asteapta intervalul specificat dupa care isi reia executia. Metoda revine imediat dupa aceea la metoda apelanta aceasta continuandu-si executia pana la expirarea cuantei de timp. } System.err. ready=true.out. } } Rezultatele afisate de program in trei executii succesive sunt redate in figura 15.join(long ms) blocheaza threadul care a efectuat apelul asteptand ms milisecunde ca threadul t caruia apelul i-a fost adresat sa “moara” intrand in starea Dead.toString()). Daca argumentul este diferit de 0. Metoda suspend() duce la trecerea threadului in starea Suspended – executia acestuia fiind suspendata pana la apelarea metodei resume() care il trece in starea Ready permitand astfel reluarea executiei acestuia. metoda intoarce true daca threadul este “viu” si false in caz contrar. IllegalThreadState Exception daca se incearca lansarea in executie a unui thread care a fost deja lansat odata anterior. Metoda “arunca” exceptia InterruptedException ca si metoda sleep(). threadul nu mai poate fi scos chiar daca se incearca relansarea lui cu metoda start(). . Metoda start() deja folosita de noi in toate exemplele anterioare permite lansarea in executie a threadului prin trecerea lui in starea Ready si amplasarea in lista de threaduri ready cu nivelul de prioritate corespunzator. memoria alocata lui poate fi eliberata (prin atribuirea valorii null variabilei care il refera) pentru a fi colectata de threadul garbage collector (un thread cu prioritate minima). Metoda isAlive() permite verificarea daca threadul este “viu” adica daca a fost lansat cu start() dar inca nu a fost oprit cu stop().println(getName()).15.lang. Daca metoda join() nu are argument sau are argument 0 asteptarea are loc pe o durata nedeterminata.Note de curs public void run(){ 187 try{ sleep(500). Metoda t.PROGRAMARE IN JAVA . Metoda “arunca” o exceptie din clasa java. O astfel de asteptare este intr-o anumita masura periculoasa deoarece poate duce fie la o amanare nedeterminata a reluarii threadului care a facut apelul fie la o interblocare a treadurilor in cazul in care treadul apelat asteapta la randul sau decesul threadului apelant.println("Exception"+ e. } catch(InterruptedException e){ System. Din acest moment.5 ¾ ¾ ¾ ¾ ¾ ¾ Fig.Rezultatul executiei programului Plantator. Metoda stop() termina executia unui thread trecandu-l in starea Dead.4 .class Numele unui thread poate fi setat si dupa instantiere cu metoda setName(String nume).

setPriority(). t2=new Thread(l2).188 CURS 15 ¾ Metoda toString() a clasei Thread intoarce un String continand numele si nivelul de prioritate al threadului precum si grupul caruia ii apartine acesta. ¾ Metoda static int enumerate(Thread tarray[]) completeaza tabloul tarray cu referinte la toate threadurile active din grupul threadului care a facut apelul. Metodele getName(). Interfata Runnable Asa cum am vazut. clasa Thread implementeaza interfata Runnable care specifica metoda publica void run(). t1. join().t2. suspend(). setDaemon(). resume(). care nu pot fi supradefinite in subclasele derivate din clasa Thread.stop(). getPriority(). Aceste clasele proprii care implementeaza interfata Runnable nu sunt threaduri dar pot fi folosite pentru a crea instante ale clasei Thread. ¾ Metoda ThreadGroup getThreadGroup() intoarce o referinta la grupul caruia ii apartine threadul.")."*"). o varianta proprie a metodei public void run(). isDaemon() si stop() sunt metode finale. care intoarce o referinta la threadul curent. ele nu mai au pe cine sa serveasca si deci pot fi “omorate” fara urmari. while(!(l1.start(). Aceasta se face pe considerentul ca daca mai exista threaduri daemon in executie. Putem folosi aceasta interfata pentru a defini propriile noastre clase care o implementeaza.isReady()&&l2. class Plantator{ public static void main(String[] argv){ Lucrator l1=new Lucrator(40. Mai multe threaduri pot fi grupate intr-un obiect ThreadGroup. O aplicatie se termina daca executia tuturor threadurilor client non-daemon s-a terminat.stop(). De regula threadurile sunt incadrate in acelasi grup cu threadul care le-a creat. String nume) La instantierea unui obiect Thread cu unul din acesti constructori va fi creat un fir de executie a carei metoda run() nu va mai fi cea implicita (care nu face nimic) fiind inlocuita cu metoda run() a clasei tinta (target) folosita la instantiere. Thread t1=new Thread(l1). In acest scop clasa Thread are definiti urmatorii doi constructori: ¾ Thread(Runnable target) ¾ Thread(Runnable target. ¾ Metoda void setDaemon(boolean on) transforma threadul intr-un thread daemon daca argumentul on are valoarea true.". getThreadGroup(). Daca un program nu are toate threadurile Un thread daemon este un thread “server” care se executa in background si la ale carui servicii apeleaza alte threaduri “client” (non-daemon)ale aplicatiei. ¾ Metoda boolean isDaemon() intoarce true daca threadul este daemon si false in caz contrar. l2=new Lucrator(40. Sa exemplificam cele aratate mai sus prin urmatorul program avand aceeasi functionalitate ca si cel din exemplul cu doi lucratori care plantau puncte si stelute la consola.isReady())). setName(). Aceste clase vor defini fiecare. . t1. Metoda intoarce numarul de threaduri plasate in tablou.start(). ¾ Clasa Thread prevede o metoda statica public static Thread currentThread(). pe langa alti diversi membri (variabile si metode).t2.

private boolean ready.yield().out. } public boolean isReady(){return ready.print(sP). deoarece metodele sleep() si yield() nu sunt definite in clasa Lucrator.} } 189 Spre deosebire de programul initial. Aceasta referinta o putem obtine apeluland metoda statica Thread. Pentru a apela alte metode nestatice ale threadului curent. clasa Lucrator si clasa Thread este reprezentata schematic in figura 15. Relatia dintre clasa Plantator. ele trebuiesc apelate cu specificarea clasei (daca sunt statice) sau obiectul caruia ii apartin.flush().i<nrP. trebuie sa obtinem referinta la instanta clasei Threed a threadului curent in care se face apelul. } catch(InterruptedException e){} System.} private void planteaza(){ try{ Thread.sleep(500).} public void run(){lucreaza(). deoarece aceste metode ale clasei Thread sunt statice le vom apela cu Thread.Note de curs } } class Lucrator implements Runnable{ private int nrP. public Lucrator(int n. String s){nrP=n.PROGRAMARE IN JAVA .getName(). Astfel pentru a apela metoda getName() am fi folosit instructiunea: Thread.6.out. System.yield(). ready=true.currentThread(). Thread.currentThread(). } private void lucreaza(){ for(int i=0. private String sP.ready=false.sleep() respectiv Thread.sP=s.i++) planteaza(). . In cazul nostru.

De exemplu unul din threaduri sa planteze ca si in exemplul precedent puncte iar celalalt sa planteze cifre cuprinse intre 0 si 9. Astfel ca o clasa care mosteneste clasa Thread nu mai poate mosteni o alta clasa ceea ce este un dezavantaj. generate aleator. In schimb o clasa care implementeaza interfata Runnable poate mosteni o alta clasa. Programul urmator defineste o . putand in acelasi timp sa serveasca pentru instantierea unui Thread. Putem crea threaduri care sa aibe atat codul cat si datele diferite.190 CURS 15 Fig. sP si ready). Threadul t1 accesa datele continute de instanta l1 a clasei Lucrator iar t2 datele continute de instanta l2 (variabilele nrP. Partajarea datelor intre threaduri In exemplul anterior cele doua threaduri aveau acelasi cod (codul metodei run() si al celorlalte metode ale clasei Lucrator prcum si codul metodelor sleep() si yeld() ale clasi Thread) dar acest cod accesa date diferite. limbajul Java nu permite mostenirea decat a unei singure clase.Relatia dintre clasa Plantator. clasa Lucrator si clasa Thread Mecanismul descris mai sus este preferabil celui bazat pe mostenire (folosit in exemplele anterioare ).15. Spre deosebire de C++ care permitea mostenirea multipla.6 .

isReady()&&l2.stop().i<nrP.isReady())). Thread t1=new Thread(l1). t1.i++) planteaza().random()*10)).t2. public Lucrator(int n){nrP=n.yield().String s){super(n).stop(). protected boolean ready.start().i++){ sP=String. t1. } ready=true. while(!(l1.start(). } catch(InterruptedException e){} System. Cele doua clase derivate au codul metodei run() diferit.i<nrP.} } class Lucrator1 extends Lucrator implements Runnable{ public Lucrator1(int n.out.Note de curs 191 clasa Lucrator care este mostenita de doua clase diferite Lucrator1 si Lucrator2 care in plus implementeaza interfata Runnable.sleep(100). ready=true. Lucrator2 l2=new Lucrator2(40).} public void run(){ for(int i=0. class Plantator{ public static void main(String[] argv){ Lucrator1 l1=new Lucrator1(40.ready=false. t2=new Thread(l2). protected String sP.PROGRAMARE IN JAVA .flush(). } public boolean isReady(){return ready. t1 prelucrand datele continute de variabilele membru ale obiectului l1 iar t2 ale obiectului l2. planteaza().". datele procesate de threaduri sunt si ele diferite.} public void run(){ for(int i=0. System.print(sP). astfel ca si threadurile create pe baza acestor doua clase difera.t2.sP=s. } .out.} protected void planteaza(){ try{ Thread.valueOf((int)(Math. Thread."). } } class Lucrator { protected int nrP. } } class Lucrator2 extends Lucrator implements Runnable{ public Lucrator2(int n){super(n).

public Prod(int d[]){data=d.length.out.currentThread().out.5}.class Mai multe threaduri cu cod diferit pot procesa un set de date comun ca in exemplul urmator in care unul din threaduri calculeaza suma iar celalalt produsul elementelor unui acelasi vector de valori intregi."Suma").isReady()&&p.7 . t1. private int produs.stop().15.t2.ready=false. for(int i=0.Rezultatul executiei programului Plantator. Thread.getName()+"="+suma).} public void run(){ produs=1. System. } } class Suma implements Runnable{ private boolean ready.i++){ suma += data[i].start(). } public boolean isReady(){return ready.t2. Thread t1=new Thread(s.192 CURS 15 } Rezultatul afisat la consola de program este prezentat in figura 15.3. Prod p=new Prod(data).4. private int data[]. System. private int suma. class Matematician{ public static void main(String[] arg){ int data[]={1. t1.7. t2=new Thread(p.i++){ produs *= data[i].println( .} public void run(){ suma=0."Produs").start(). i<data. } ready=true.2. i<data. for(int i=0.length.isReady())).yield(). while(!(s. Suma s=new Suma(data).stop().println( Thread. Fig.ready=false. private int data[]. public Suma(int d[]){data=d.} } class Prod implements Runnable{ private boolean ready.

8 Rezultatele afisate la executia programului Matematician. La instantierea threadurilor s-au folosit constructori in varianta care seteaza si numele threadului.yield(). Metoda main() creaza o instanta s a clasei Suma si o instanta p a clasei Prod. s si p sunt folosite fiecare la instantierea a cate unui thread – t1 si respectiv t2. astfel incat metodele run() ale celor doua obiecte s si p.class . Astfel threadul t1 va avea numele “Suma” si metoda run() a lui s calculand suma iar t2 va avea numele “Produs” si metoda run() a lui p calculand produsul elementelor aceluiasi tablou de intregi data. Fig. metodele run ale acestora afiseaza si rezultatele intermediare obtinute pe parcursul procesarii datelor.} } Cele doua threaduri au codul metodei run() diferit fiind construiti pe baza a doua obiecte Runnable diferite. } public boolean isReady(){return ready. Primul calculeaza suma elementelor unui tablou de intregi iar celalalt produasul elementelor unui tablou de intregi. In figura 15. } ready=true.currentThread(). Pentru a pune in evidenta functionarea concurenta a threadurilor.15. desi au codul diferit vor procesa de fapt acelasi date.8 sunt prezentate rezultatele afisate de program. Cele doua obiecte Runnable.getName()+"="+produs).Note de curs 193 Thread. specificand ca argument al constructorilor o referinta la acelasi tablou de date data.PROGRAMARE IN JAVA . Tabloul de intregi prelucrat de fiecare thread este referit de variabila membru data initializata de constructorul clasei cu o referinta primita ca argument. Thread.

1 – Rezultatele afisate de programul Plantator. } public boolean isReady(){return ready.16.} public void run(){ for(int i=0.yield(). } } Fig.t2. private String sP. while(!(l1.isReady())). Daca semaforul are culoarea verde sau bratul este ridicat trenul poate trece."). Aici in acest scop se folosesc semafoare – fie luminoase. el . Thread. ready=true. Vom folosi o variabila booleana de tip “flag” care daca are valoarea true permite threadului t1 sa planteze un punct iar daca are valoarea false va permite threadului t2 sa “planteze” o steluta.i++) planteaza().PROGRAMARE IN JAVA . t1."*").class Daca analizam rezultatele afisate de programul precedent.ready=false. trebuie sa gasim un mecanism ajutator pentru sincronizarea activitatii celor doua threaduri. System. String s){nrP=n. rosu si verde.". l2=new Lucrator(40. t1. fie mecanice cu un brat. o steluta). prezentate in figura 16.t2. Ne putem inspira din mecanismele utilizat in dirijarea traficului feroviar.flush().sP=s. alteori reuseste celalalt thread sa planteze cateva stelute succesiv.isReady()&&l2. cu doua culori.stop().out.i<nrP.start(). Thread t1=new Thread(l1). } } class Lucrator implements Runnable{ private int nrP. private boolean ready. Daca t1 gaseste “flagul” avand valoarea false.out.stop().1 vom vedea ca desi concurente.start(). public Lucrator(int n. t2=new Thread(l2).} private void planteaza(){ System. In caz contrar trenul trebuie sa astepte culoarea verde sau ridicarea bratului semaforului. cele doua threaduri “planteaza” “produsele” lor ( puncte si stelute) asincron – uneori reuseste unul dintre ele sa planteze cateva puncte succesiv.print(sP). Daca dorim ca punctele si stelutele sa fie “plantate” succesiv ( un punct.Note de curs 193 Curs 16 Sincronizarea firelor de executie Fie programul urmator care utilizeaza doua threaduri Lucrator pentru a “planta” puncte si stelute pe ecran: class Plantator{ public static void main(String[] argv){ Lucrator l1=new Lucrator(40.

yield(). } } class Semafor{ private boolean flag. this."T2").} public void schimba(){ flag=!flag. private boolean ready.40.i<nrP. t2=new Thread(l2.stop(). t1.out.currentThread(). public Lucrator(Semafor semafor.ready=false. semafor. int n. l2=new Lucrator(semafor. System. } } class Lucrator implements Runnable{ private Semafor semafor. Un obiect – instanta a clasei Semafor – este creat si referinta catre acesta transmisa constructorului celor doua obiecte Runnable l1 si l2.start(). daca t2 gaseste “flagul” avand valoarea true va trebui sa astepte ca acesta sa capete valoarea false pentru a-si “planta” steluta. Lucrator l1=new Lucrator(semafor.").// comuta threadul } ready=true.} } Aici am definit o clasa Semafor care incapsuleaza “flag”-ul alaturi de procedurile de setare si testare a starii acestuia.194 CURS 16 va trebui sa astepte ca acesta sa capete valoarea true pentru a-si “planta” punctul. El va fi o resursa comuna pentru cele doua threaduri t1 si t2 care prin apelarea . private String sP."."T1").} public void run(){ for(int i=0.equals("T1")) while(!semafor.semafor=semafor. t1. } private void planteaza(){ System.stop().print(sP). while(!(l1.schimba(). } public boolean isReady(){return ready.sP=s.i++){ if(Thread.} public boolean verdeT1(){return flag. Programul este urmatorul: class Plantator{ public static void main(String[] argv){ Semafor semafor=new Semafor().out.flush(). threadul curent va comuta “flagul” pe pozitia complementara pentru a-si interzice o noua “plantare” si in acelasi timp pentru a autoriza celalalt thread sa isi faca “plantarea”.isReady()&&l2. Dupa ce “plantarea” a fost efectuata. La fel.//T1 asteapta culoarea verde else while(!semafor. String s) { nrP=n.t2.verdeT1()). Thread t1=new Thread(l1.//T2 asteapta culoarea verde planteaza().// autorizeaza celalalt thread Thread. public Semafor(){flag=false.start().verdeT2())."*").getName().t2. private int nrP.} public boolean verdeT2(){return !flag.40.isReady())).

si acestea asezandu-se la coada si asteptand aparitia cheii. o secventa de cod sa fie garantat executata doar de un singur thread si numai unul. se obtine apeland metoda getName() stringul continand numele threadului curent si se face comparatia la egalitate cu numele threadului t1 (“T1”) apeland metoda clasei String.Note de curs 195 metodelor sale vor putea sa determine si sa modifice starea flagului sincronizandu-si activitatea in functie de aceasta. Daca valoarea obtinuta este true inseamna ca threadul curent este t1 si se apeleaza metoda semafor. fiecare .PROGRAMARE IN JAVA . In functie de valoarea booleana astfel obtinuta. Pana intr-un punct. se obtine referinta la threadul curent apeland metoda statica Thread. amandoua primesc textele lucrand in paralel – prima de la director iar cealalta de la contabilul sef. Pentru a patrunde in incapere.verdeT1() intoarce false.2: Sincronizarea sectiunilor critice ale threadurilor Fig. Daca in timp ce incaperea este ocupata de un thread un alt thread doreste sa patrunda in incapere. Programul va afisa la executie rezultatele din figura 16. ciclul de asteptare este terminat si threadul curent efectueaza “plantarea” comutand apoi semaforul prin apelul metodei semafor. Aceasta metoda intoarce true daca numele threadului curent este “T1” si false in caz contrar.16. equals(“T1”). Tot in paralel. in cadrul unui bloc de selectie dublu if/else. Astfel.2 – Rezultatele afisate de programul Plantator.verdeT2() intoarce false. Ciclul while se executa atat timp cit semafor. nu va gasi cheia (aceasta fiind detinuta de threadul care se afla deja in incapere) si atunci se va aseza la coada asteptand aparitia cheii. threadul pune cheia la loc. La iesirea din incapere. Daca in acest moment ar incepe sa bata la masina concurent. in cadrul acestui cod se face identificarea dupa nume a threadului curent.currentThread(). Daca threadul curent nu este t1. va lua cheia si va patrunde in incapere. Odata obtinuta permisiunea de “plantare”.verdeT1() in cadrul unui ciclu while care implementeaza operatia de asteptare. Celalalte threaduri care trebuie sa execute si ele acea secventa astepta pana ce threadul care a inceput executia acesteia sa o si parcurga pana la capat (chiar daca pentru executia secventei respective ii sunt necesare mai multe cuante de timp) Acest mecanism se aplica de regula secventelor critice de program a caror executie concurenta de catre doua sau mai multe threaduri ar duce la o functionare incorecta a programului. Acelasi lucru se va intampla si cu alte threaduri care vor sa intre in incapere. fiecare se indreapta spre masina de scris care din pacate este numai una. Threadul pastreaza cheia asupra sa cat timp se afla in incapere incaperea. Ca sa dam un exemplu din lumea reala sa luam cazul in care doua dactilografe au de batut doua texte diferite la masina de scris. se fac procesarile adecvate threadului in cauza. autorizand astfel iesirea din ciclul de asteptare a threadului colaborator si trecandu-se pe sine in starea de asteptare.schimba(). un thread trebuie sa ia cheia cu care sa descuie usa de acces. Desi t1 si t2 au acelasi cod (aceeasi metoda run() a clasei Lucrator). De fapt aceasta trebuie privita mai curand ca o cheie cu care se poate descuia o usa spre o incapere din obiectul respectiv. Aceasta cheie este obiectului. In momentul in care incaperea este libera si cheia este disponibila threadul aflat primul la coada va iesi din starea de asteptare. atunci el este threadul t2 si se executa ciclul while de asteptare cat timp semafor. Acest mecanism permite ca in cazul mai multor threaduri ruland concurent. folosind aceasta referinta. orice obiect din clasa Object sau dintr-o subclasa a acesteia are o proprietate numita lock – lacat.class in versiunea sincronizata In limbajul Java.

isReady()&&maria. private MasinaDeScris ms. Solutia este ca sa se asigure accesul la masina de scris numai a unei singure dactilografe. } } class MasinaDeScris { public void print(char c){ try{ Thread. Dactilografa care a ajuns prima la masina de scris si a ocupat-o.yield(). nu o elibereaza decat atunci cand a terminat de dactilografiat textul propriu."Ana").ms=ms. } public boolean isReady(){return ready.i<doc. toate celalalte threaduri care vor incerca sa execute aceeasi secventa vor fi blocate intr-o coada de asteptare pana cand threadul care deja executa secventa nu o va termina iesind din blocul sincronizat. textul imprimat ar fi un mixaj neinteligibil al celor doua texte. private String doc.stop().sleep(10). } ready=true. maria=new Dactilografa(ms..196 CURS 16 textul sau.1/06.1999\n". // executa activitatea critica }// paraseste incaperea si elibereaza cheia In momentul in care un threadul incepe sa execute aceasta secventa. } } class Dactilografa implements Runnable { private boolean ready. public Dactilografa(MasinaDeScris ms. class Office{ public static void main(String[] argv){ MasinaDeScris ms=new MasinaDeScris(). apoi cealalta.doc2).doc1). t1. Dactilografa ana=new Dactilografa(ms. t1.i++){ ms. this.print(doc. doc2="Nota Contabila Nr.} public void run(){ for(int i=0.start(). Sa urmarim urmatorul program care modeleaza accesul la o singura masina de scris a doua dactilografe. } . while(!(ana.1/06.isReady())).String doc){ this.length(). cealalta trebuind sa astepte eliberarea masinii de scris pentru a putea incepe dactilografierea propriului text. t2=new Thread(maria.1999\n".start()..charAt(i)).doc=doc. Thread t1=new Thread(ana.t2. Thread."Maria"). In program sectiunea critica a unui thread se inscrie intr-un bloc care este “sincronizat” cu un obiect ( de regula cu obiectul careia ii apartine codul): sinchronized(obj){ // ia cheia si intra in incapere .stop(). una apasand o tasta. Mecanismul care asigura un astfel de mod de lucru a acestei sectiuni critice din activitatea dactilografelor este cel descris anterior.t2. String doc1="Directiva Nr.

stop(). t1.3 sunt redate rezultatele a trei executii succesive ale programului care confirma necesitatea accesului sincronizat al dactilografelor la masina de scris. t1.Note de curs catch(InterruptedException exception){} System.t2.yield().out.t2.16."Maria").1999\n".doc=doc. Thread.1999\n".length().ms=ms.String doc){ this.isReady()&&maria. while(!(ana.PROGRAMARE IN JAVA .1/06. maria=new Dactilografa(ms.1/06.print(doc.} public void run(){ synchronized(ms){ for(int i=0. private MasinaDeScris ms.3 – Rezultatele afisate de programul Office. } } .start().start().doc1).i<doc.charAt(i)).stop().print(c). private String doc.i++){ ms. public Dactilografa(MasinaDeScris ms. Thread t1=new Thread(ana. this. Dactilografa ana=new Dactilografa(ms. } public boolean isReady(){return ready.flush().class Pentru a asigura accesul sincronizat va trebui sa redefinim clasa MasinaDeScris ca subclasa a clasi Object (pentru a putea folosi un obiect din aceasta clasa pentru sincronizare) si sa incadram sectiunea critica din metoda run() intr-un bloc de sincronizare cu obiectul ms (instanta a clasei MasinaDeScris). } } ready=true. String doc1="Directiva Nr.isReady())). System. doc2="Nota Contabila Nr. } } 197 In figura 16. } } class Dactilografa implements Runnable { private boolean ready."Ana"). Programul rezultat este urmatorul: class Office{ public static void main(String[] argv){ MasinaDeScris ms=new MasinaDeScris().doc2). Fig.out. t2=new Thread(maria.

.4.4 – Rezultatele afisate de programul Office. sincronizarea ofera un mecanism care permite partajarea resurselor intre threaduri. Ca urmare t1 va incepe sa execute corpul instructiunii if moment in care expira cuanta de timp alocata executiei sale si threadul este trecut in starea Ready.out.198 CURS 16 class MasinaDeScris extends Object { public void print(char c){ try{ Thread. } unde zi. } catch(InterruptedException exception){} System.16. In acest exemplu. va incrementa variabila luna moment in care ii expira si lui cuanta de . public void up(){ zi++. De regula o resursa partajata intre mai multe threaduri este un obiect continand informatia in variabilele sale membru.. Am vazut ca in cazul programelor cu un singur fir de executie (singlethread) pentru a asigura accesarea corecta a acestor date. if(zi > nrZileInLuna(luna.. Sa presupunem ca threadul t1 incepe executia acestei secvente si incrementand variabila zi obtine o valoare mai mare ca numarul de zile in luna respectiva. va inscrie valoarea 1 in variabila zi. an sunt variabile membru ale obiectului din clasa Resursa. variabilele trebuie sa fie declarate private iar obiectul sa fie prevazut cu metode publice adecvate pentru accesarea si eventual procesarea acestor date.sleep(10). o instanta a clasei MasinaDeScris era o resursa folosita in comun de catre cele doua threaduri Dactilografa. Sa presupunem ca un al doilea thread t2 incepe executia aceleiasi secvente. .an)){ zi=1. partajat intre threadurile t1 si t2. El va incrementa variabila zi si va obtine o valoare mai mare ca numarul de zile in luna si va incepe la randul sau sa execute corpul instructiunii de selectie if.print(c). . Metode sincronizate.class Asa cum am vazut in exemplul precedent. monitoare Fig. Sa consideram urmatoarea secventa de instructiuni din cadrul unei metode: class Resursa { private int zi. System... } } Rezultatele afisate de program sunt redate in figura 16. luna++.out. In cazul programelor cu mai multe fire de executie (multithread) trebuiesc luate masuri suplimentare de siguranta pentru prevenirea coruperea datelor datorita executiei concurente de catre mai multe threaduri ale metodelor obiectului. luna.flush()..// procesare an } } .luna.an.

. Sa ne imaginam urmatorul scenariu.. Metoda m1. executia fiind reluata de threadul t1 din punctul in care a fost intrerupt adica in corpul instructiunii de selectie. Pentru sincronizare se va folosi chiar obiectul partajat referit cu this.PROGRAMARE IN JAVA .luna. Acesta la randul sau apeleaza metoda m2.f1().. Metodele monitoarelor m1 si m2 sunt apelate de doua threaduri t1 si t2 astfel: t1 apeleaza m1. Apeland metoda m1. cand intreg corpul metodei este sincronizat chiar cu obiectul caruia metoda ii apartine (referinta la acesta fiind this). El va inscrie in variabila zi valoarea 1 si va incrementa variabila luna. } In acest caz.. public synchronized void up(){ zi++. Fenomenul are loc in urmatoarele conditii. Pentru a evita astfel de situatii secventa data trebuie sincronizata cu un obiect prevenind astfel executia concurenta a metodei de catre threadul t2 in timp ce ea este executata si de t1..an)){ zi=1. .// procesare an } } .f1() si isi insuseste cheia de la monitorul .f1().an.// procesare an } } } .f1() apeleaza metoda m2. Interblocarea threadurilor La proiectarea programelor Java multithread trebuie avut grija sa se evite interblocarea threadurilor.. subclasa a clasei Object: class Resursa extends Object{ private int zi. Intr-o astfel de executie. care face parte din clasa Resursa. public void up(){ synchronized(this){ zi++.f1() apeleaza metoda m1. luna++.. .an. variabila luna a fost incrementata de doua ori in loc sa fie incrementata odata ceea ce evident duce la un rezultat eronat(s-a sarit peste o luna). Threadul t2 va fi trecut in starea Waiting si pus intr-o coada de asteptare la obiectul folosit pentru sincronizare pana cand t1 va termina executia metodei.. } Se spune despre metoda up ca este sincronizata. if(zi > nrZileInLuna(luna..Note de curs 199 timp. el este intrerupt si intra in executie threadul t2. if(zi > nrZileInLuna(luna.f2() iar metoda m2.f2(). .. luna++.an)){ zi=1. Un obiect care contine cel putin o metoda sincronizata se numeste monitor.luna. Fiecare dispune de metodele sincronizate f1() si f2().f1() iar t2 pe m2.. Daca in acest moment ii expira cuanta de timp alocata.. limbajul Java prevede o scriere prescurtata echivalenta: class Resursa extends Object{ private int zi. Sa presupunem ca avem doua monitoare m1 si m2. . threadul t1 isi insusseste cheia de la monitorul m1.

. Invalidarea simulata cu repaint() are acelasi efect ca si o expunere reala cauzand activarea threadului AWT care va apela metoda paint() corespunzatoare.200 CURS 16 m2. aceasta va apela metoda m1. Cand se doreste redesenarea ferestrei se apeleaza metoda repaint() a componentei AWT. Metodele executate de thread pentru procesarea evenimentului trebuie sa fie cat mai scurte pentru ca daca ele efectueaza o procesare de durata mai mare. se lanseaza inca un thread secundar care implementeaza functiile AWT gestionand evenimentele si executand metodele handleEvent() si paint() ale interfetei. Daca aceasta durata este prea mare ea devine sesizabila operatorului si duce la o functionare greoaie a programului. la un moment dat va apela metoda m2. consta in crearea unui thread server insarcinat cu aceasta procesare de durata. In figura 16. nu exista decat un singur thread care gestioneaza intregul sistem de componente AWT. acesta avand sarcina doar sa activeze threadul server fiind liber in continuare sa preia si sa trateze alte evenimente. provocand astfel redesenarea ei. Solutia pentru evitarea inconvenientul prezentat. aceasta intarziere devine deja sesizabila si incomodeaza.f2().f2(). threadul AWT va fi ocupat cu aceasta procesare si nu va putea sa preia un nou eveniment pana nu termina procesarea. Threadul t2 nu detine cheia de la monitorul m1 (aceasta fiind inca in posesia threadului intrerupt t1) asa ca se va bloca asteptand ca t1 sa elibereze cheia. care simuleaza expunerea intregii suprafete a acesteia. Aceasta are o consecinta importanta. acestei metode. Daca programul creaza o interfata grafica. La reactivarea threadului t1 pentru o noua cuanta de timp. Dar t2 se afla de asemenea in starea Waiting de asteptare pana cand threadul t1 va elibera cheia de la m1 si in consecinta cele doua threaduri raman blocate definitiv asteptandu-se reciproc. care raspunde cu intarziere la comenzile date prin intermediul interfetei grafice. Starile prin care trec cele doua threaduri sunt prezentate in figura 16. Firele de executie in AWT Chiar si la executia unui program singlethread Java se lanseaza pe langa threadul principal si doua threaduri utilitare de prioritate scazuta – unul pentru colectarea blocurilor de memorie eliberate si unul pentru finalizatori ( care executa metodele finalize() la distrugerea obiectelor). Evenimentul survenit intre timp va fi preluat din coada de evenimente si tratat cu o intarziere egala cu durata procesarii evenimentului precedent. acest thread este in majoritatea timpului in asteptare fiind activat numai la aparitia unui eveniment cum ar fi apasarea unei taste sau miscari ale soarecului si atunci cand o portiune din fereastra a fost invalidata prin acopreirea de catre alta fereastra ceea ce necesita redesenarea portiunii “expuse”. “apasarea” butonului va fi sesizata de thread abia dupa terminarea procesarii in curs. Daca insa procesarea dureaza secunde. Chiar daca interfata grafica consta din mai multe ferestre deschise cu mai multe componente fiecare. De exemplu daca interfata este prevazuta cu butonul “Abort” care ar trebui sa inchida fereastra si sa termine aplicatia. Deoarece nu detine cheia de la monitorul m2 (aceasta fiind in posesia threadului t2) se va bloca asteptand ca t2 sa elibereze cheia. Continuind executia. Crearea acestuia degreveaza threadul AWT de sarcina unei procesarii indelungate.f1().5a sunt reprezentate starile prin care trece threadul AWT in cazul prezentat mai sus.5b. Executand aceasta metoda. Daca durata acestei procesari este de ordinul milisecundelor utilizatorul nu va sesiza intarzierea. acesta va continua executia din punctul in care a fost intrerupt adica din interiorul metodei m1.

*.5 Starile threadului AWT la procesarea de durata a unui eveniment Ca exemplu sa analizam programul urmator: import java.16. public MyFrame(){ super("Test AWT thread").awt. . setLayout(new FlowLayout()).100).PROGRAMARE IN JAVA .id==e. class MyFrame extends Frame{ private Button b.Note de curs 201 Fig. } public boolean handleEvent(Event e){ if(e. b=new Button("Procesare").resize(300.show().WINDOW_DESTROY){ hide(). add(b).

threadul revine in starea Suspended prin apelul metodei suspend().i<10000000.000 de iteratii in cadrul metodei run() (pe durata a mai multe cuante de timp. interfata grafica a fost completata cu un camp text pentru afisarea starii threadului “Server” printr-un mesaj adecvat.000 de iteratii ale ciclului for din metoda action(). terminand astfel aplicatia.000. return true. solutia este crearea unui thread “Server” care sa deserveasca threadul AWT.6) .000 de iteratii) .i++). } public static void main(String[] args){ MyFrame f=new MyFrame().000 de iteratii care iau un timp considerabil ( de circa 10 secunde). si gasind aici evenimentul WINDOW_DESTROY se va activa executand metoda handleEvent() pentru acest eveniment. Daca se actioneaza butonul de sistem “x” se genereaza un eveniment cu identificatorul WINDOW_DESTROY care va fi tratat de tratat de metoda handleEvent() prin inchiderea ferestrei si terminarea programului. In acest program. programul va fi terminat cvasiinstantaneu la actionarea butonului de sistem “x” chiar daca se afla in cursul procesarii initiate prin actionarea .Sarcina threadului AWT la aparitia evenimentului de la butonul “Procesare” se reduce doar la activarea threadului server.000. Programul urmator pune in practica considerentele enuntate mai sus.000. Object o){ for(long i=0. } } Acest program creaza o fereastra cu un buton avand eticheta “Procesare” (figura 16. Daca se actioneaza butonul “Procesare” si imediat butonul de terminare. Aceasta se explica prin faptul ca threadul AWT care a fost activat de evenimentul generat la actionarea butonului “Procesare” este ocupat cu executia celor 10. fiind astfel degrevat de sarcina procesarii indelungate si fiind rapid gata de tratarea unui nou eveniment.handleEvent(e). Fig.16. preluand asupra sa procesarea evenimentelor de actionare a butonului “Procesare” (efectuarea celor 10.exit(0). Dupa terminarea celor 10. Abia dupa ce termina executia acestei metode si revine in starea de asteptare a evenimentelor de la interfata grafica.6 Fereastra afisata de programul MyFrame. } public boolean action(Event e. CURS 16 } return super. programul nu se va termina imediat.000.202 dispose(). Conform celor aratate anterior. trecand un timp de circa 10 secunde pana la inchiderea ferestrei si terminarea programului. Activarea threadului “Server” se face de catre metoda action() prin apelul la metoda resume() a acestuia avand ca efect trecerea lui din starea Suspended in starea Ready si facandu-l astfel eligibil pentru a fi trecut de planificator in starea Running pe o cuanta de timp. In aceasta versiune.class Metoda action() a clasei MyFrame trateaza evenimentele produse la actionarea acest buton prin executarea unui ciclu for cu 10. fiind executat concurent cu threadul principal si cu thredul AWT). return true. System.

suspend(). o va redimensiona la 300x100 pixeli si o va face vizibila pe ecran. Aceasta din urma creaza fereastra.PROGRAMARE IN JAVA . public MyFrame(){ super("Test AWT thread").msg). In continuare metoda main() steaza threadul server ca Daemon si il activeaza prin apelul metodei start() a acestuia. return true. f.i++). Threadul server incepe executia metodei run() definita in clasa Server.*. setLayout(new FlowLayout()). private Button b.setText("Server thread running").server). campul text de afisare a starii threadului server.handleEvent(e)..show().t.stop(). } public static void main(String[] args){ MyFrame f=new MyFrame(). private TextField msg.setText("Server thread suspended"). butonul. Object o){ t. } return super.Note de curs butonului“Procesare”.awt.setDaemon(true). hide().add(msg). private Thread t.){ msg.t=new Thread(f. } public boolean handleEvent(Event e){ if(e. f. return true. obiectul Runnable server si cu ajutorul acestuia threadul ce va deservi threadul AWT pentru procesare.setEditable(false). b=new Button("Procesare"). Programul sursa este redat mai jos: import java. f.t. va adauga aceste componente ferestrei. f.server=new Server(f. } } } 203 Programul incepe prin a defini clasa MyFrame al carei constructor va crea.resize(300. dispose(). msg=new TextField(30). class MyFrame extends Frame{ private Server server.100).exit(0).WINDOW_DESTROY){ t.currentThread(). public Server(TextField msg){this. for(long i=0.} public void run(){ for(. } } class Server implements Runnable{ private TextField msg. Thread.id==e. add(b).msg=msg. msg. si dupa afisarea mesajului de stare intra imediat in starea Suspended prin . } public boolean action(Event e.start(). va crea si seta managerul de amplasare al ferestrei. msg. System. Tot in clasa MyFrame sunt definite metodele de tratare a evenimentelor handleEvent() si action() precum si metoda statica main().resume(). i<10000000.

afisiand un mesaj de stare adecvat si efectuand procesarea (cele 10. Din aceasta stare nu va iesi decat in urma executiei de catre threadul AWT a metodei acction() la tratarea evenimentului de actionare a butonului “Procesare”. termina executia threadului server apeland metoda stop() a acestuia. La apasarea butonului de sistem “x” threadul AWT executa metoda handleEvent() in cadrul careia detecteaza evenimentul WINDOW_DESTROY asociat acestei actiuni. inchide fereastra si termina aplicatia. Fig.class . La executia acestei metode threadul AWT va apela metoda resume() a threadului server reactivandu-l.000 de iteratii ale ciclului for ). Treadul server reactivat va relua executia concurenta a metodei run() din punctul in care a fost suspendat.7 Fereastra afisata de programul MyFrame.000.7 este redata ferastra aplicatiei cu mesajele de stare a threadului. threadul va relua executia ciclului infinit al metodei.204 CURS 16 apelul metodei sale suspend() . In figura 16. La terminarea iteratiilor. afisand din nou mesajul de suspenadare si apeland metoda sa suspend() care il va aduce iar in starea Suspended pana la o noua apasare a butonului “Procesare”.16.

Activitatile executate de producatori si consumatori au durate diferite ele desfasurandu-se asincron. In consecinta. mestesugarul va reitera succesiv urmatorul lant de operatii – va debita dintr-un colac de sarma de otel o bucata de lungimea necesara. Activitatea unui program singlethread putea fi asemuita cu munca din atelierul unui mestesugar in carea acesta face singur toate operatiile de prelucrare asupra materiei prime pentru obtinerea in final a produsului finit. Astfel vom avea trei categorii de muncitori – unii care efectueaza operatia de debitare. Intr-o astfel de organizare a productiei muncitorii de specializari diferite trebuie sa coopereze transmitand de la unul la altul produsele intermediare. Producatorul executa produsul si incearca sa-l depuna intr-o cutie. De exemplu pentru a fabrica ace. De exemplu un muncitor care face operatia de debitare joaca rolul de producator. In cazul exemplului nostru sincronizarea se desfasoara astfel. facand astfel loc pentru depunerea a noi produse. In a doua varianta in care durata operatiei de prelucrare efectuata de consumator este mai mica decat cea efectuata de producator. Cutia in care producatorii depun iar consumatorii ridica produsele joaca rol de tampon (buffer in limba engleza) intre acestia servind la sincronizarea activitatii lor. La elaborarea programului trebuie tinut cont de regulile de sincronizare a threadurilor si de partajare a datelor discutate in cursul precedent. La randul sau acelasi muncitor joaca rolul de producator in relatia sa cu muncitorul care executa gaurirea acelor ascutite de el.Note de curs 205 Curs 17 Comunicatia intre threaduri Asa cum am vazut in exemplele anterioare programele multithread se proiecteaza pornind de la ideia cooperarii a doua sau mai multe threaduri la rezolvarea problemei. Intr-o astfel de cooperare unii muncitori joaca rolul de producatori iar altii de consumator. threadurile avand rolul producatorconsumator similar muncitorilor specializati pe operatii diferite din cazul prezentat. Astfel operatia de debitare a sarmei s-ar putea sa aibe o durata mai mica decat cea de ascutire a unei astfel de bucati. Muncitorul care ia bucatile de sarma debitate de colegul sau si le ascute la un capat joaca rolul de consumator. Activitatea unui program multhithread poate fi comparata cu productia dintr-o intreprindere industriala in care se aplica diviziunea muncii. consumatorul va gasi cutia goala si va astepta ca producatorul sa depuna in ea un produs. Daca cutia este deja plina el se opreste asteptand ca partenerul sau sa consume din stoc. In cazul programelor multithreading proiectarea acestora se poate face pornind de la analogia cu o astfel de intreprindere descrisa mai sus. Sa analizam programul urmator: . va ascuti aceasta bucata de sarma la unul din capete si ii va executa un orificiu la celalalt capat.PROGRAMARE IN JAVA . Activitatea producatorconsumator trebuie deci sincronizata. avand mai multi lucratori specializati intr-o singura operatie. altii care ascut bucatile de sarma la un capat si altii care executa orificiile de la celalalt capat obtinand produsul finit. stocul de bucati debitate ar creste continuu deoarece muncitorul care efectueaza ascutirea nu are timp sa consume intreaga productie a colegului sau. Pentru mari eficienta prin reducerea timpilor de asteptare pot fi prevazuti in prima varianta mai multi consumatori la un singur producator si mai multi producatori la un singur consumator in cea de a doua.

buf=buf. Buffer buf){ sb=new StringBuffer().prod).stop(). prod. public Producator(TextField msg. msg1.setEditable(false). return true.c=new Consumator(f. private Buffer buf. } public boolean action(Event e. f.b). private Button b.setPartner(f. private Thread partner. f. f. setLayout(new FlowLayout()).prod. } public static void main(String[] args){ MyFrame f=new MyFrame(). this.cons. dispose(). public MyFrame(){ super("Test Producator .start(). private Thread prod.p=new Producator(f.c.show(). System.f. add(b).add(msg2).resize(300.id==e.disable().cons.buf. msg1=new TextField(30).cons=new Thread(f.206 CURS 17 import java. } return super. cons.msg2. f.start().buf=new Buffer().handleEvent(e). b=new Button("Start").cons).partner=partner. private int k. this.prod=new Thread(f.msg=msg.msg1.setPartner(f. } } class Producator implements Runnable{ private TextField msg.f. f. f.p). f. f. msg2.add(msg1).exit(0). return true. private StringBuffer sb. } public boolean handleEvent(Event e){ if(e.buf). class MyFrame extends Frame{ private Producator p.} . } public void setPartner(Thread partner){this.100).p.setEditable(false).stop().*.c). hide(). private Consumator c.f. f.msg2. Object o){ b.awt. private TextField msg1. msg2=new TextField(3).Consumator").resume().WINDOW_DESTROY){ prod. private Buffer buf.

partner=partner..setLength(0).} public void run(){ for(. } b. public void store(int val){data=val. Amandoua threadurile intra imediat in starea Suspended prin executia in prima instructiune a ciclului cu contor a apelului Thread.b=b.toString()). La actionarea butonului “Start”. Odata creati si activati in metoda main() prin apelul metodelor start() ale threadurilor. msg.random()*10)). sum+=buf.resume().){ for(int i=0. } public void setPartner(Thread partner){this. } sb.sum=0.){ for(int i=0. try{ Thread.resume().append(k+" ").} } 207 Aici producatorul este modelat de threadul prod construit pe baza unui obiect Runnable din clasa Producator.suspend(). msg.suspend(). if(i<4)partner.buf=buf. private Thread partner. Aceste metode contin doua cicluri incuibate for – ciclul exterior fiind un ciclu infinit iar al cel interior un ciclu cu contor cu 5 iteratii.enable().i<5. } catch(InterruptedException ex){} buf. Button b){ this.Note de curs public void run(){ for(.msg=msg.get().setText(String.currentThread(). respectiv Consumator.. } } } class Consumator implements Runnable{ private TextField msg. partner. Buffer buf.PROGRAMARE IN JAVA .setText(sb.currentThread().store(k=1+(int)(Math.sleep(1000). construit pe baza unui obiect Runnable din clasa Consumator. sb.i++){ Thread.i++){ Thread. producatorul si consumatorul incep executia metodelor run() definite in clasele Runnable Producator.valueOf(sum)). threadul AWT executa metoda action() dezactivand .i<5.} public int get(){ return data.currentThread(). Consumatorul este modelat printr-un thread cons. } } } class Buffer{ private int data.suspend(). private Button b. public Consumator(TextField msg. private Buffer buf. this. this.

Consumatorul la randul sau dupa preluarea ultimei date generate de producator din buffer.suspend() care il aduce din nou in starea Suspended. in timpul generarii si procesarii datelor cand threadurile se activeaza reciproc si dupa terminarea procesarii unui set de 5 date.currentThread().suspend() care il aduce din nou in starea Suspended. El nu mai este reactivat de consumator in ultima iteratie ramanand in aceasta stare.11 – Activitatea threadurilor producator-consumator . Dupa iesirea din ciclul cu contro. aceste cicluri se repeta pana la terminarea a cinci iteratii in urma carora in campul text gestionat de producator se gasesc afisate cele 5 numere generate iar in cel gestionat de consumator suma acestor numere. Fig. Dupa aceasta threadul producator adauga numarul generat la un StringBuffer si afiseaza continutul acestuia intr-un camp text needitabil. testand si incrementand contorul i si apeland dupa aceea Thread.store() definita in clasa Buffer. prin inceperea executiei a unui nou ciclu cu contor.currentThread().currentThread(). In figura 17.currentThread().208 CURS 17 butonul si apeland metoda prod. initializeaza contorul i al ciclului interior cu 0 si executa apelul Thread. cand threadurile sunt din nou suspendate.resume() care va activa threadul producator. threadul producator activeaza threadul consumator prin apelul metodei resume() a acestuia. consumatorul trece la o noua iteratie a ciclului. contorul de iteratii i este testat si incrementat dupa care producatorul executa din nou instructiunea Thread.suspend() intrand si el in starea Suspended. Depunerea se face apeland metoda buf. Activitatea descrisa mai sus a threadurilor producator si consumator va fi reluata numai dupa o noua actionare a butonului “Start”. calcularea si afisare sumei iese din ciclul cu contor fara sa mai apeleze metoda resume a producatorului.suspend() care il aduce din nou in starea Suspended. Dupa afisare consumatorul reactiveaza threadul producator prin apelul metodei acestuia resume()( daca contorul i<4 adica daca nu este ultima iteratie). In acest timp. consumatorul care a fost activat de producator preia data din buffer cu apelul metodei buf. Producatorul elaboreaza dupa o temporizare de 1 secunda un numar aleator cuprins intre 1 si 10 si il depune intr-un obiect buf din clasa Buffer avand capacitate de stocare de o valoare intreaga.get() si o aduna la variabila sum (initializata cu 0) afisand noua valoare a acesteia intr-un camp text needitabil.17. cu aceasta prima iteratie se termina. La a cincea iteratie threadul producator dupa generarea si afisarea numarului incepe o noua iteratie a ciclului exterior.1 sunt redate imagini ale ferestrei aplicatiei in cele trei faze de executie a threadurilor – inainte de apasarea butonului cand ambele threduri sunt suspendate. Dupa afisarea numarului. consumatorul reactiveaza butonul “Start” si incepe o noua iteratie a ciclului infinit. initializeaza contorul i si variabila sum la 0 si executa apelul Thread. Dupa aceasta.

id==e.stop().handleEvent(e).Consumator"). msg1.resize(300. msg2=new TextField(3). procesorul este nefolosit.add(msg2).cons. pana reuseste. setLayout(new FlowLayout()). in mod intentionat am introdus o temporizare in secventa de “producere” a numarului aleator.setEditable(false). In exemplul precedent. In aceasta perioada de timp. } public boolean handleEvent(Event e){ if(e. threadul consumator isi petrece o mare parte din timp in asteptare. vom modifica programul anterior pentru a implementa aceleasi functiuni dar folosind pentru comunicatie mecanismul descris mai sus. .PROGRAMARE IN JAVA . In acest caz utilizarea metodele suspend() si resume() devine incomoda. Utilizarea acestor metode devine dificila in cazul cooperarii intre mai mult de dou threaduri. msg1=new TextField(30).exit(0). Am putea mari eficienta aplicatiei daca am introduce mai multe threaduri producatoare. hide(). b=new Button("Start"). private TextField msg1.add(msg1). Am vazut ca instantele acestor clase implementeaza o coada de asteptare la care se ataseaza threadurile care incearca sa acceseze metodele sincronizate ale obiectului in perioada in care “cheia” acestuia este detinuta de un alt thread care executa o astfel de metoda sincronizata. definite in clasa Object si in subclasele acesteia. Un thread poate sa se ataseze de buna voie la coada de asteptare trecand astfel in starea Waiting prin apelul metodei wait() a acestuia. private Buffer buf. private Thread prod. msg2. Deoarece “consumul” este mult mai rapid.*. public MyFrame(){ super("Test Producator . private Button b. import java. In plus. cons. dispose(). Blocurile de instructiuni in care se apeleaza metodele wait() si notify() trebuie sa fie sincronizate.awt. Intrucat daca aceasta metoda esueaza. Limbajul Java prevede pentru sincronizarea comunicatiilor intre threaduri un mecanism bazat pe doua metode – wait() si notify(). metoda wait() “arunca” o exceptie din clasa InterruptedException si deci trebuie apelata in cadrul unui bloc try urmat de un bloc catch. ea trebuie apelata din nou si din nou.stop(). Threadul va iesi din aceasta stare cand un alt thread va apela metoda notify() a aceluiasi obiect. } return super. add(b).Note de curs 209 Comunicatia folosind metodele wait() si notify() Aplicatia din exemplul precedent asigura comunicatia intre doua threaduri folosind metodele suspend() si resume(). class MyFrame extends Frame{ private Producator p. De aceea de regula se incadreaza intr-un ciclu while sau do/while care se executa atat timp cat apelul metodei esueaza. Pentru a exemplifica acest mecanism.100).show().setEditable(false).msg2. System.WINDOW_DESTROY){ prod. private Consumator c. return true.

disable().210 CURS 17 } public boolean action(Event e. private StringBuffer sb. private Buffer buf.c). f. public Producator(TextField msg. f.buf=buf. f. f. this.suspend(). } public void run(){ for(. this.){ Thread. return true. } } class Producator implements Runnable{ private TextField msg.msg2. } public static void main(String[] args){ MyFrame f=new MyFrame(). Object o){ b. sb.buf).. private Button b. Buffer buf){ sb=new StringBuffer(). } public void run(){ for(. for(int i=0.resume(). Button b){ this.msg=msg.i++){ sum+=buf.i++){ try{ Thread.setLength(0). private int k. .toString()).append(k+" ").enable().c=new Consumator(f.prod=new Thread(f.i<5.sleep(1000).f..msg1.start().buf.msg=msg.start().setText(sb.f.buf=new Buffer(). f. } b.store(k=1+(int)(Math.i<5.get().currentThread().cons. Buffer buf. this. this.b). public Consumator(TextField msg.random()*10)).p=new Producator(f.prod.p). private Buffer buf.valueOf(sum)).b=b. prod. msg. } catch(InterruptedException ex){} buf. } sb.setText(String.f. f.){ for(int i=0. f.buf=buf. msg. } } } class Consumator implements Runnable{ private TextField msg.cons=new Thread(f. sum=0.

Consumatorul reinitializeaza controrul si suma la 0 intrand in asteptarea furnizarii unei noi date in buffer. Clasa Vector Clasa Vector definita in pachetul java. Un obiect din aceasta clasa va creste automat (alocindu-si dinamic memoria necesara) atunci cand ii sunt adaugate noi elemente. Constructorii clasei Vecor sunt: ¾ Vector() – construieste un vector cu capacitatea de 10 elemente. actualizeaza suma si o afiseaza dupa care trece la urmatoarea iteratie procesul repetandu-se de 5 ori. threadul producator executand metoda store() apeleaza metoda notify() care “trezeste” treadul consumator din starea de asteptare. ciclul producator reseteaza StringBufferul si intra din nou in starea Suspended. Dupa ce data a fost inscrisa. Elementele vectorului sunt instante ale clasei Object sau subclase ale acesteia si deci atunci cand se doreste adaugarea in vector a unor date primitive (cum ar fi date de tipul int ) se va recurge tot la obiecte din clasele corespunzatoare (cum ar fi Integer pentru date de tip int ).Note de curs } } } class Buffer extends Object{ private int data. in acest scop el apeleaza metoda sincronizata get().} }while(isException) return data. el apeleaza la inceputul ei metoda wait() si intra intr-o stare de asteptare. ¾ Vector(int cp) – construieste un vector cu capacitatea de cp elemente.PROGRAMARE IN JAVA . Threadul consumator genereaza numarul aleator. do{ try{ wait(). . La actionarea butonului “Start” este executata de catre thradul AWT metoda action care apeleaza metoda resume() a threadului producator care este astfel activat. } } 211 Deosebirile fata de programul anterior constau in urmatoarele: La pornire threadul productor este suspendat dar threadul consumator este activ si incearca sa preia o data din Buffer. Dupa a cincea iteratie ciclul cu contor se termina. Executand aceasta metoda. } public synchronized int get(){ boolean isException. il afiseaza si apeleaza metoda sincronizata store a bufferului pentru a-l inscrie. Threadul producator revine din metoda store si incepe sa genereze o noua data in timp ce threadul consumator revine in metoda sa run(). In plus clasa permite operatii suplimentare cum ar fi eliminarea unui element din vector sau inserterea unui nou element in interiorul vectorului.util implementeaza o structura de tip tablou cu alocare dinamica de memorie. } catch(InterruptedException exception){isException=true. isException=false. Aceasta clasa este utila atunci cand numarul de elemente ale tabloului nu este dinainte cunoscut. notify(). Procesul descris mai sus se reia dupa o noua actionare a butonului. public synchronized void store(int val){ data=val.

In caz contrar intoarce false. Cautarea incepe de la indexul start catre inceputul vectorului. ¾ final synchronized int indexOf(Object elm. int start) – intoarce indexul primului element elm din vector sau –1 daca elementul nu este gasit. pe prima pozitie libera obiectul obj.212 CURS 17 ¾ Vector(int cp. capacitatea vectorului este marita cu valoarea din variabila protejata capacityIncrement. ¾ final int capacity() – intoarce capacitatea vectorului. ¾ final synchronized void setElementAt(Object elm. ¾ final synchronized boolean removeElement(Object elm) – elimina elementul elm din vector daca il gaseste si intoarce true. Sa exemplificam utilizarea unui obiect din clasa Vector ca buffer in cazul unui program cu mai multe threaduri producator si un singur thread consumator. ¾ final synchronized String toString() – intoarce un string continand toate elementele vectorului. Daca aceasta este zero. ¾ final synchronized void copyInto(Object tablou[]) – copiaza elementele vectorului intr-un tablou static (standard) ¾ final synchronized Object elementAt(int index) – intoarce obiectul de la pozitia index din vector.intoarce primul element din vector. daca nu mai este loc. capacitatea vectorului se dubleaza. ¾ final synchronized void setSize(int sz) – seteaza o noua dimensiune a vectorului sz. int start) – intoarce indexul primului element elm din vector sau –1 daca elementul nu este gasit. final synchronized int lastIndexOf(Object elm. ¾ final int size() – intoarce dimensiunea vectorului.int index) – inserteaza elementul elm pe pozitia index. ¾ final boolean isEmpty() – intoarce true daca vectorul nu conine nici un element si false in caz contrar.intoarce ultimul element din vector. Aceasta clasa este ideala pentru a asigura comunicarea dintre threaduri. majoritatea fiind sincronizate. Programul este prezentat mai jos: . ¾ final synchronized void ensureCapacity(int cp) – redimensioneaza vectorul asigurand o capacitate de cp elemente ¾ final int indexOf(Object elm) – intoarce indexul primului element elm din vector sau –1 daca elementul nu este gasit. ¾ final synchronized void trimToSize() – redimensioneaza vectorul la dimensiunea minima necesara pentru stocarea elementelor deja continute de vector. ¾ final synchronized Object firstElement() . ¾ final synchronized int lastIndexOf(Object elm) – intoarce indexul ultimului element elm din vector sau –1 daca elementul nu este gasit.int index) – inlocuieste elementul de pe pozitia index cu elementul elm. ¾ final synchronized Object lastElement() . Cautarea incepe de la indexul start spre sfarsitul vectorului. cand vectorul trebuie sa creasca. ¾ final synchronized void removeElementAt(int index) – elimina din vector elementul de pe pozitia index. ¾ final synchronized void removeAllElements() – sterge toate elementele vectorului. Se vede din metodele enumerate mai sus ca aceasta clasa este proiectata pentru a fi folosita in programele multithreading. capacitatea lui creste cu cpIncr. Metodele clasei sunt: ¾ final sinchronized void addElement(Object obj) – adauga la vector. ¾ final synchronized void insertElementAt(Object elm. int cpIncr) – construieste un vector cu capacitatea de cp elemente.

Daca in asteptare se afla mai multe threaduri. Daca in momentul in care un thread apeleaza metoda notify() a unui obiect nu exista nici un thread in asteptare. Dupa expirarea acestei perioade de timp.PROGRAMARE IN JAVA . numai unul va fi reactivat fara ca sa stim cu certitudine care. notificarea respectiva este pierduta. threadul este reactivat.Note de curs 213 Metodele wait() si notify() au o proprietate foarte importanta. Limbajul Java in mod intentionat (pentru a asigura un mare grad de libertate la implementarea limbajului) nu garanteaza ca threadul reactivat prin apelul metodei notify() este un anumit thread (de exemplu primul sosit in coada de asteptare). ca argument al metodei. Acesta este motivul pentru care aceste metode se folosesc de regula in asociere cu o variabila flag. Daca se doreste activarea garantata a threadurilor in ordinea sosirii in coada se procedeaza ca in exemplul urmator: . De asemenea metioda wait() mai are doua versiuni in care threadul este pus in starea de asteptare pe o perioada de timp (de timeout ) specificata in milisecunde sau milisecunde si nanosecunde. Mai trebuie specificat de asemenea in legatura cu metodele wait() si notify() un amanunt important.

i<10.. Runnable r = new Run(fifoQueue).start().currentThread().Note de curs 217 Curs 18 Controlul activarii threadurilor Asa cum am vazut. trebuie sa introducem un mecanism ajutator cum ar fi cel din exemplul urmator: import java..PROGRAMARE IN JAVA . lacat.size()!=0){// exista threaduri in asteptare lacat=lacate. Limbajul Java nu specifica pe care dintre ele.removeElementAt(0). try{ lacat.i++){ t=new Thread(r).sleep( (long)(Math.// un nou lacat synchronized (lacat){// ia cheia de la lacat lacate..// adauga lacatul in oprite System.util.wait(). class FiFo{// controleaza ordinea FIFO de activare a thredurilor private Vector lacate = new Vector().getName()+" in asteptare").random()*500)).i++){ try{ Thread.// ia primul lacat lacate. t. threadurile care intra in asteptare prin apelul metodei white() a unui monitor fiind plasate intr-o coada de asteptare din care sunt reactivate prin apelul metodei notify() a monitorului.*.// elimina-l din de vector } } if(lacat!=null){ synchronized(lacat){ // ia cheia si. Aceasta metoda activeaza un singur thread din cele aflate in asteptare.i<10.out. // lanseaza-l in executie } // reactiveaza 10 threaduri for(int i=0.. Thread t. public void oprire(){ Object lacat=new Object().// creaza un thread nou si. synchronized(lacate){ if(lacate. // activeaza thredului care asteapta // la acest lacat } } } public static void main(String[] args){ FiFo fifoQueue=new FiFo().firstElement().//elibereaza cheia si asteapta activarea } catch(InterruptedException e){} } } public void restart(){ Object lacat=null. // lanseaza 10 threaduri for(int i=0.// asteapta un timp .notify().addElement(lacat).println( Thread. daca dorim ca threadurile sa fie activate in ordinea sosirii.

Fiecare dintre acestea acceseaza sincronizat metoda oprire() a clasei FiFo (First in.out. queue.18.1 Mesajele afisate de programul FiFo. } } } class Run implements Runnable{ FiFo queue. public Run(FiFo fifoQueue){queue=fifoQueue.oprire(). la fiecare acces se creaza un obiect lacat din clasa Object adaugat ca element nou vectorului .currentThread(). } } Fig. In cadrul acestei metode.println( Thread. First out).getName()+" in executie").restart().currentThread().println( Thread. System.out.class Programul creaza si executa 10 threaduri. fifoQueue.218 CURS 18 } catch (InterruptedException e){} System.out.getName()+" restartat").println( "Reactivare un thread din coada FIFO").} public void run(){ System.

incepand cu indexul offset. 2. Comunicarea prin streamuri Un stream (curent.int offset. rupand legatura cu sursa de date. Apeland ulterior metoda reset(). 9. 7. ¾ synchronized void mark(int limita) – pune un marcaj in pozitia curenta din stream. Limbajul Java defineste in pachetul java. ¾ void close() throws IOException – “Inchide” streamul. Consumatorul “absoarbe” datele din rezervorul de date printr-un stream de intrare asa cum trage o pompa apa dintr-un put. int len) throws IOException – citeste din stream in tabloul b.1 ne confirma functionarea acestui mecanism in conformitate cu cele aratate anterior. ¾ boolean markSupported() intoarce true daca streamul curent suporta marcarea. In acest fel cele 10 threaduri vor fi restartate exact in ordinea in care au fost oprite. se poate reveni din pozitia respectiva la pozitia astfel marcata. 10. ele nu pot fi folosite pentru instantieri de obiecte ci numai pentru a defini metodele necesare pentru a asigura transferul datelor de la rezervor la consumator respectiv de la producator spre rezervor. Daca se depaseste aceasta limita. Producatorul pompeaza datele printr-un stream de iesire in rezervor asa cum pompa trimite apa prin conducta in chiuveta. Din mesajele afisate la reactivare se observa ca threadurile au fost restartate in aceeasi ordine. 4. Pentru a reactiva threadurile exact in ordinea in care acestea au intrat in starea de asteptare threadul principal va apela succesiv metoda restart() a clasei FiFo. Fiind clase abstracte. ¾ int read() throws IOException – citeste si intoarce un octet din stream. Aceste metode sunt: .io doua tipuri abstracte de streamuri derivate din clasa Object: ¾ InputStream – stream de intrare ¾ OutputStream – stream de iesire. Dupa aceea threadul care a creat un obiect lacat apeleaza metoda wait() a acestuia intrand in starea de asteptare. 8.Note de curs 219 lacate.pentru clasa InputStream ¾ InputStream() – constructorul clasei ¾ int avaiable() throws IOException –intoarce numarul de octeti disponibili in stream. Mesajele afisate de aplicatie si prezentate in figura 18. Intoarce -1 daca s-a semnalat sfarsitul de fisier – (fizic sau un caracter de control corespunzator) ¾ int read(byte b[]) throws IOException – citeste din stream numarul de octeti necesar in tabloul b. In acest fel toate cele 10 threaduri se vor afla in stare de asteptare atasate fiecare la propriul sau obiect lacat plasat in ordinea crearii (si deci in ordinea opririi theadurilor) in vectorul lacate. Intoarce numarul de octeti citit sau -1 daca s-a semnalat sfarsitul de fisier – (fizic sau un caracter de control corespunzator) . 6. Parametrul limit specifica numarul de octeti care poate fi citit diincolo de marcaj. Intoarce numarul de octeti citit (in mod normal cat dimensiunea tabloului) sau -1 daca s-a semnalat sfarsitul de fisier – (fizic sau un caracter de control corespunzator) ¾ int read(byte b[]. flux) de date poate fi privit ca o conducta de legatura intre un rezervor de date si un consumator (stream de intrare) sau intre un produator si un rezervor de date de date(stream de iesire).PROGRAMARE IN JAVA . cel mult numarul de octeti specificat de parametrul len. In acest exemplu ordinea de intrare in starea Waiting a threadurilor a fost 1. 3. marcajul este sters. Aceasta va extrage din vector obiectele lacat incepand cu primul (deci exact in ordinea in care au fost introduse) si apeland metoda notify() pentru fiecare astfel de element. 5.

instantiaza un stream de intrare din clasa PipedInputStream. ¾ PipedInputStream(PipedOutputStream src) throws IOException – constructorul . Inainte de a fi folosit. int offset.2 Fig. Prin conectarea ca sursa de date a unui astfel stream de iesire a unui thread producator cu un stream de intrare al unui thread consumator se poate realiza comunicarea intre cele doua threaduri asa cum este reprezentata in figura 18. in clasele derivate cu bufferizare (cum este de exemplu System. int len) throws IOException – inscrie in stream cel mult len octeti continuti de tabloul b incepand cu indexul offset. limbajul Java defineste printre altele subclasele PipedInputStream respectiv PipedOutputStream. ¾ void write(int b[]. Pornind de la aceste clase abstracte. ¾ void flush() throws IOException – in aceasta clasa metoda nu face nimic. acesta va trebui conectat la un stream de iesire instanta a clasei PipedOutputStream.18. “fortand” transmisia octetilor continuti de acesta in rezervor.2 Comunicatia intre threaduri realizata prin streamuri Metodele clasi PipedInputStream sunt: ¾ PipedInputStream() – constructorul clasei. rupand legatura cu rezervorul de date.220 CURS 18 ¾ synchronized void reset() throws IOException – restabileste pozitia curenta in stream pe marcajul stabilit cu metoda mark().out) poate fi folosita pentru a “goli” bufferul in stream. ¾ long skip(long num) throws IOException – sare in stream peste numarul specificat de octeti . ¾ abstract void write(int b) throws IOException – inscrie octetul b in stream. ¾ void write(int b[]) throws IOException – inscrie toti octetii continuti de tabloul b in stream.pentru clasa OutputStream ¾ OutputStream() – constructorul clasei ¾ void close() throws IOException – “Inchide” streamul.

¾ abstract void write(int b) throws IOException – inscrie octetul b in stream. void close() throws IOException – “Inchide” streamul. ¾ void connect(PipedInputStream dest) throws IOException. instanta a clasei PipedOutputStream.isRunning() || c. int read() throws IOException – citeste si intoarce un octet din stream.getStream()).connectTo(c.int offset. instanta a clasei PipedOutputStream. rx. ¾ PipedOutputStream (PipedInputStream dest) throws IOException – constructorul clasei. rx. tx. int read(byte b[]. Inainte de a fi folosit.start(). public Producator(PipedOutputStream out){ this. Atunci cand un thread citeste dintr-un stream de intrare apeland metoda read() a acestuia. int len) throws IOException – citeste len octeti din stream. instantiaza un stream de iesire din clasa PipedOutputStream. PipedOutputStream out=new PipedOutputStream(). instanta a clasei PipedInputStream. void connect(PipedOutputStream src) throws IOException. Intoarce numarul de octeti citit.conecteaza streamul de iesire la streamul de intrare specificat. int offset. dest. private boolean running. Producator p=new Producator(out). el este blocat pana cand operatia de citire nu este terminata ( pana octetul sau blocul de octeti nu a fost efectiv preluat de la sursa de date care s-ar putea sa intarzie furnizarea acestora). } } class Producator implements Runnable{ private PipedOutputStream out. Thread tx=new Thread(p).stop(). int len) throws IOException – inscrie in stream len octeti continuti de tabloul b incepand cu indexul offset. import java. Programul urmator exemplifica utilizarea streamurilor in comunicatia dintre threaduri. . p. memorandu-i ca elemente ale tabloului b incepand cu indexul offset. ¾ void write(int b[]. instantiaza un stream de iesire din clasa PipedOutputStream conectandu-l la streamul de intrare dest.conecteaza streamul de intrare la streamul de iesire specificat. rx=new Thread(c).out=out.io. rupand legatura cu streamul sursa de date.start().isRunning()). while(p. instanta a clasei PipedInputStream. tx. acesta va trebui conectat la un stream de iesire instanta a clasei PipedInputStream. class RxTx { public static void main(String[] args){ PipedInputStream in=new PipedInputStream().*.stop(). instantiaza un stream de intrare din clasa PipedInputStream conectandu-l la streamul de iesire src. Consumator c=new Consumator(in).PROGRAMARE IN JAVA . Metodele clasi PipedOutputStream sunt: ¾ PipedOutputStream() – constructorul clasei. ¾ void close() throws IOException – informeaza streamul receptor ca a receptionat ultimul sau octet si “inchide” efectiv streamul rupand legatura. src.Note de curs 221 ¾ ¾ ¾ ¾ clasei.

random()*1000)).read()) !=-1){ System.toString()). } catch(Exception ex){ System.connect(in).sleep((long)(Math. ex."). System. try{ while((val=(byte)in... out. private boolean running.print("Citesc "+(byte)val +" ")..yield().out.out.toString()).. Thread. i<5.OK. try{ for(int i=0. } } } class Consumator implements Runnable{ private PipedInputStream in.random()*256). running=false. ex.OK.currentThread().println(ex. } } public boolean isRunning(){ return running..printStackTrace().out. } } } . System. running=false.currentThread().out.out.random()*1000))...").println(ex.} public void run(){ byte val.write(val).printStackTrace().println(". Thread.println("Legatura inchisa.} public void run(){ byte val. } System.").yield(). public Consumator(PipedInputStream in){ this.i++){ val=(byte)(Math.out.print("Scriu "+ val+" ").println(". } public void connectTo(PipedInputStream in){ try{ out. } out. } public PipedInputStream getStream(){ return (in).in=in. Thread. } catch(Exception ex){ System. System.sleep((long)(Math..toString()).close(). Thread. } catch (Exception ex){ System.printStackTrace(). ex.out.222 CURS 18 running=true. } public boolean isRunning(){ return running. running=true.println(ex.out.

¾ final synchronized void destroy() – distruge grupul fara a afecta starea threadurilor componente. De asemenea se creaza doua obiecte Runnable p si c. La randul lor obiectele Runnable p si c sunt folosite la instantierea threadurilor tx respectiv rx. Toate threadurile dintr-un grup se pot accesa reciproc si pot accesa threadurile din ThreadGroup-urile subordonate (copil) dar nu pot accesa thredurile din ThreadGroup-ul parinte si din ThreadGroupurile de deasupra acestuia. Referintale la streamurile in si out sunt memorate in c respectiv p. Threadul producator tx. Threadul consumator rx. In momentul in care ambele metode intorc valoarea false threadul principal opreste cele doua threaduri rx si tx si se termina.class Gestionarea grupurilor de threaduri Deoarece thread-urile sunt procese in mare masura independente este uneori avantajos ca ele sa fie grupate pentru a gestiona mai eficient activitatea lor. . ¾ ThreadGroup(ThreadGroup parinte. dupa care inchide streamul de intrare si se termina. In plus aceasta clasa permite introducerea unei relatii ierarhice intre threadurile apartinand unor grupuri diferite. String nume) – constructor al clasei.18. executand metoda run() a clasei c citeste din streamul de intrare in valori de tip byte pana cand valoarea citita este egala cu –1 indicand ca sursa de date s-a terminat (sfarsit de fisier).PROGRAMARE IN JAVA . Clasa ThreadGroup permite crearea unor “colectii” de threaduri. ¾ synchronized int activeGroupCount() – intoarce numarul de grupuri active de threaduri din grup. executand metoda run() a clasei p genereaza 5 valori aleatoare de tip byte si le scrie in streamul de iesire out dupa care inchide streamul si se termina. ¾ synchronized int activeCount() – intoarce numarul de threaduri active din grup. Clasa ThreadGroup are urmatoarele metode: ¾ ThreadGroup(String nume) – constructor al clasei.3 Fig. instante ale claselor Producator respectiv Consumator. Ambele threaduri semnaleaza terminarea prin inscrierea valorii false in variabila proprie running. Grupul de threaduri instantiat primeste numele nume si are ca parinte ThreadGroup-ul specificat prin argumentul parinte. Threadul principal monitorizeaza executia celor doua threaduri rx si tx prin verificarea valorii acestei variabile prin apelul metodelor isRunning().3 mesajele afisate la executia programului RxTx.Note de curs 223 In cadrul metodei main() a clasei RxTx se creaza perechea de streamuri de date in si out din clasele PipedInputStream respectiv PipedOutputStream. Astfel un ThreadGrup poate sa aiba un ThreadGroup parinte. Grupul de threaduri instantiat primeste numele nume. Mesajele afisate la executia programului sunt prezentate in figura 18.

¾ int enumerate(Thread list[]. boolean recursiv) – Daca parametrul recursiv are valoarea true plaseaza in tabloul list cate o referinta la fiecare thread din grup si din grupurile subordonate. syncronized void list() – afiseaza lista tuturor threadurilor si ThreadGroup-urilor continute la consola sistemului (System. Din exemplele precedente se observa avantajele deosebite pe care le prezinta programarea concurenta in comparatie cu programarea clasica. final String getName() – intoarce un string continand numele grupului. final synchronized void setMaxPriority(int nivel) – seteaza nivelul de prioritate al tuturor threadurilor nou create in grup la valoarea nivel.out). Intoarce numarul de elemente ale tabloului. final synchronized void stop() – apeleaza metoda stop() pentru toate threadurile din grup si din grupurile copil subordonate. ¾ int enumerate(ThreadGroup list[]) – Plaseaza in tabloul list cate o referinta la fiecare ThreadGroup copil subordonat grupului. final synchronized void suspend() – apeleaza metoda suspend() pentru toate threadurile din grup si din grupurile copil subordonate. final ThreadGroup getParent() – intoarce o referinta la ThreadGroup-ul parinte. utile in proiectarea aplicatiilor cu mai multe fire de executie. String toString() – intoarce un string continand numele grupului si nivelul maxim de prioritate al threadurilor continute de acesta.224 CURS 18 ¾ int enumerate(Thread list[]) – Plaseaza in tabloul list cate o referinta la fiecare thread al grupului. detalierea continuand pana la . final boolean parentOf(ThreadGroup altGrup) – intoarce true daca grupul este parintele lui altGrup. final void setDaemon(boolean daemon) – seteaza flagul daemon al grupului. void uncaughtException(Thread t. problemele de complexitate mare fiind descompuse in subprobleme mai putin complexe care la randul sau erau descompuse in subprobleme mai simple. Abordarea problemei se facea prin aplicarea metodologiei topdown constand in rafinari succesive de la complex la simplu. ¾ int enumerate(ThreadGroup list[]. Throwable e) – este o metoda apelata de sistem pentru exceptiile “neprinse” Organizarea cooperarii intre threaduri Mecanismele de comunicatie inthre threaduri descrise anerior pot fi folosite pentru implementarea unor mecanisme mult mai complexe. final boolean isDaemon() – intoarce valoarea flagului daemon din acest grup. Daca parametrul recursiv are valoarea false atunci va plasa in tabloul list cate o referinta numai la threadurile din grup. final synchronized void resume() – apeleaza metoda resume() pentru toate threadurile din grup si din grupurile copil subordonate. Intoarce numarul de elemente ale tabloului. Toate threadurile create in acest grup vor “mosteni” acest flag.boolean recursiv) – Daca parametrul recursiv are valoarea true plaseaza in tabloul list cate o referinta la fiecare ThreadGroup copil subordonat grupului si la toate ThreadGroup-urile subordonate ThreadGroup-urilor copil. etc . In programarea procedurala aplicatia era organizata sub forma unui ansamblu de proceduri a caror aplicare succesiva asupra datelor de intrare ducea intr-un final la obtinerea rezultatelor. final int getMaxPriority() – intoarce prioritatea maxima a thredurilor din grup (acestea pot avea prioritati diferite). Intoarce numarul de elemente ale tabloului. Intoarce numarul de elemente ale tabloului.

Avem doua threaduri – unul producator si altul consumator. Programarea orientata presupune o abordare complet diferita. Organizarea activitatii threadurilor cuprinde doua laturi. Fig. Intr-o astfel de relatie. executanti. Prima care priveste organizarea modului de acces la resurse ( folosirea in comun a obiectelor-utilaje) iar a doua priveste organizarea modului de cooperare intre threadurile – executant. se construiesc module cu functionalitati noi si de complexitate mai ridicata. Astfel pornind de la module existente cu o functionalitate adecvata. Sa analizam pentru exemplificarea cooperarii intre threaduri cazul urmator. Setul de proceduri si succesiunaea apelurilor acestora reproducea etapele de detaliere ale problemei. unul dintre threaduri joaca rolul de client iar celalalt de server. La randul sau chelnerul apeleaza de data aceasta in calitate de client la serviciile bucatarului iar bucatarul la serviciile ajutoarelor sale. Programarea concurenta deschide perspective noi in proiectarea aplicatiilor completand facilitatile oferite de programarea orientata obiect.4. procesul continuind pana la obtinerea produsului final capabil de rezolvarea problemei date (metodologia down-top). Threadurile Prod si Cons sunt componente active ale aplicatiei. O astfel de relatie este mai mult decat relatia producator-consumator implementata de noi in exemplele anterioare. a threadurilor-executanti care sa le foloseasca pentru prelucrarea datelor si organizarea activitatii eficiente a acestora pentru obtinerea rezultatelor. Mecanismul de comunicatie dintre client si server din momentul in care clientul a solicitat un serviciu serverului pana in momentul in care este servit si poate sa-si continue activitatea se numeste rendez-vous. threadurile apeleaza la metodele a diverse obiectelor la fel cum muncitorii folosesc diverse utilaje si instrumente pentru prelucrarea materiei prime pentru obtinerea produselor finite. iar obiectul Buffer este o componente pasive folosita de executanti pentru . care la randul lor se folosesc pentru a realiza module si mai complexe. Threadul-client in activitatea desfasurata apeleaza la serviciile oferite de threadul-server asa cum clientul unui restaurant apeleaza la serviciile oferite de chelner.18. Intr-o astfel de abordare aplicatia poate fi gandita facand analogia dintre activitatea threadurilor si activitatea unor persoane care coopereaza pentru obtinerea unui produs final. Intr-unul din exemplele anterioare transferul de date intre cele doua threaduri se facea prin intermediul unui buffer un obiect care implementa metodele store() si get(). constand in proiectarea structurii aplicatiei pe principii asemanatoare proiectarii hardware. Proiectarea aplicatia consta in definirea obiectelor-utilaje. Interactiunea dintre threaduri si acest buffer putem sa o reprezentam schematic ca in figura 18. Intr-o astfel de abordare.4 – Transferul de date intre threaduri prin intermediul unui obiect buffer In acest caz threadurile se folosesc de obiectul buffer asa cum muncitorii se folosesc de un utilaj. In activitatea de prelucrare a datelor .PROGRAMARE IN JAVA .Note de curs 225 obtinerea unui set de subprobleme a caror rezolvare nu mai prezenta dificultate si riscul unor erori era redus la minim.produs finit. relatia dintre doua threaduri care coopereaza este aceea de client-server.

fiind dupa cum am mai spus autonome. In cazul pe care ni-l propunem sa-l analizam vom inlocui obiectul pasiv buffer cu un al treilea thread care va fi solicitat de catre producator sa primeasca si sa pastreze temporar datele produse iar de catre consumator sa-i inmaneze datele detinute.5.18. apeland la serviciile serverului. Clientul trezeste serverul si incepe sa astepte sa fie servit. cooperarea dintre threaduri se desfasoara dupa urmatorul scenariu. In cazul nostru. Aici incepe practic rendez-vous –ul dintre client si server. Clientul isi termina asteptarea si isi reia activitatea (prelucrarea datei obtinute de la server). Acest al treilea thread joaca rolul de server in timp ce thredurile producator si consumator joaca rolul clientilor. Serverul la randul sau isi va continua activitatea acceptand o cerere la intrarea get. Schematic. Daca serverul este in acel moment ocupat cu alte treburi. Cand threadul Cons se hotaraste sa preia date de buffer el va accesa intrarea get. Componenta pasiva. Fig. Aici va gasi clientul care a adormit asteptandu-l cu cererea in mana. Cele mai frecvente cazuri sunt insa cele in care un thread server apeleaza la randul lui la serviciile altor threaduri pentru care el este client. Serverul va prelua cererea clientului care continua sa astepte terminarea rendez-vous-ului. Spre exemplul threadul Prod a generat o data si vrea sa o transmita spre pastrare bufferului. Serverul preia cererea clientului. El incearca sa acceseze intrarea store a acestuia. Pentru aceasta el deschide intrarea get unde sa presupunem ca nu gaseste nici un client in asteptare. extrage data si o inmineaza cluientului moment in care care rendezvous-ul se termina. rendez-vous-ul dintre client si server incepe imediat. Componentele active le-am reprezentat prin paralelograme pentru a sublinia caracterul lor paralel (concurent). clientul va gasi aceasta intrare inchisa si va incepe sa astepte ca ea sa se deschida. threadul server Buffer are doua intrari – store si get fiecare intrare corespunzind unui serviciu oferit de server. Dupa un anumit interval de timp serverul isi termina treburile cu care era ocupat si accepta cereri de servicii pe intrarea store. cooperarea dintre cele trei threaduri se poate reprezenta ca in figura 18. Serverul se intoarce si el la treburile sale putand de . primite de la threadul producator. moment in care care rendez-vous-ul se termina. va stoca data intr-o variabila interna si il va “trezi” pe client.5 Cooperarea dintre threaduri client si server Spre deosebire de threadurile client care sunt autonome. l-am reprezentat asa cum ne-am obisnuit deja printr-un dreptunghi.226 CURS 18 realizarea unor operatii asupra datelor. In acest exemplu threadurile client nu au intrari. In aceste conditii serverul se aseaza comod si incepe sa astepte el sosirea la aceasta intrare a unui client cu o cerere de extragere a unei date. Clientul se va intoarce la treburile sale ( generarea unei noi date). Intrucat o gaseste deschisa cu serverul in asteptare de clienti. descizand-o.

Deoarece spre deosebire de limbajul Ada. pune . putand fi imaginate si alte variante in care de exemplu clientul daca gaseste intrarea inchisa asteapta numai un timp limitat sau de loc rendez-vous-ul. La crearea obiectului. Un astfel de monitor se poate construi prin instantierea unei clase ce va mosteni clasa Object (care permite definirea de metode sincronizate) si va avea definite doua variabile membru : ¾ public int cients – destinata contorizarii threadurilor-client aflate in asteptare pentru a fi servite. Daca intrarea este inchisa.open == true . Fig.18.Note de curs 227 exemplu accepta din nou o cerere la intrarea store. Daca serverul a deschis intrarea si se afla in asteptarea unei cereri aceasta variabila are valoarea true. poate sa o inchida imediat la loc si sa se indrepte spre cealalta intrare fara sa mai astepte deloc.6. ¾ public boolean open – specificand starea intrarii.6 Diagrama desfasurarii in timp a executiei threadurilor Aceasta este numai o varianta de scenariu de cooperare clienti-server.PROGRAMARE IN JAVA . De asemenea serverul daca nu gaseste un client la deschiderea unei intrari.serverul este in asteptare de clienti) notyifica serverul. Java nu este prevazut cu un suport pentru acest tip de comunicatie. De asemenea clasa va fi completata cu definitia unei metode sincronizate ce implementeaza serviciul oferit de server: ¾ public synchronized <tip rezultat> request(<lista parametri>) – incrementeaza contorul de clienti si daca intrarea este deschisa (entry. Diagrama desfasurarii in timp a executiei celor trei threaduri este prezentata in figura 18. De asemenea sunt posibile scenarii in care mai multi clienti incearca sa acceseze o intrare a serverului si gasind-o inchisa sau serverul fiind ocupat cu servirea unui client ( un rendez-vous este in curs de desfasurare) se aseaza intr-o coada asteptand disciplinati sa le vina randul sa fie serviti. intrarea este inchisa si deci vriabila este initializata cu valoarea false. La crearea obiectului nici un client nu se va afla in asteptare la aceasta intrare si deci vriabila este initializata cu valoarea 0. implementarea acestui mecanism avansat de coorperare intre threaduri se poate construi prin utilizarea unor monitoare de tip semafor pentru modelarea intrarilor threadului server.

228

CURS 18

threadul client in asteptare. Dupa notificarea de catre server se executa sectiunea metodei ce implementeaza serviciul cerut. Pe de alta parte obiectul Runnable folosit la constructia serverului va defini si metoda ¾ private void accept(Entry entry) – care, daca nu sunt clienti in asteptare (entry.clients==0), va deschide intrarea (entry.open==true) si va pune serverul in asteptare. Daca sunt clienti in asteptare va notifica pe unul dintre ei (entry.notify()), declansand astfel continuarea executiei de catre acesta a sectiunii metodei entry.request() care implementeaza serviciul cerut. De asemenea mecanismul de rendez-vous poate fi implementat mult mai simplu folosind pentru comunicatie streamuri din clasa PipedInputStream si PipedOutputStream.

PROGRAMARE IN JAVA - Note de curs

229

Curs 19
Fisiere
Datele (date initiale, rezultate intermediare si rezultatele finale) memorate in variabile pe perioada executiei programului sunt pierdute in momentul in care variabilele respective expira si sunt distruse sau la terminarea programului. Fisierele sunt folosite pentru pastrarea pentru un timp indelungat a unui volum mare de date, chiar si dupa ce programul care le-a creat isi termina executia. Datele pastrate in fisiere sunt numite si date persistente. In claculator, fisierele sunt pastrate in dispozitivele de memorie auxiliara cum ar fi discuri si benzi magnetice sau discuri optice si gestionate de sistemul de operare. Aceasta inseamna ca operatii cu fisiere precum cautarea, crearea, stergerea, redenumirea, accesarea (scrierea/citirea in/din fisiere) si altele asemenea se fac de aplicatie prin apelul rutinelor corespunzatoare ale sistemului de operare. Dupa modul de acces al aplicatiilor la datele pastrate in fisiere, acestea se pot clasifica in fisiere cu acces secvential si fisiere cu acces aleator.

Ierarhizarea datelor
Datorita faptului ca dispozitivele de memorie ale calculatoarelor sunt realizate cu elemente cu doua stari (avand capacitatea de un bit), datele sunt stocate in aceste dispozitive sub forma binara, fiind reprezentate prin prin succesiuni de valori 1 si 0. Fiecare astfel de valoare este memorata intr-un element de memorie prin setarea starii sale in una din cele doua posibile, corespunzator valorii memorate. pentru memorarea unei date vor fi deci necesare mai multe elemente binare de memorie. Pentru pastrarea datelor, memoria se aloca in blocuri de avand capacitatea de 1 byte = 8 bit ( 8 elemente binare). Astfel pentru memorarea unei date se vor aloca unul su mai multe blocuri cu capacitatea de 1 byte, atat cat este necesar pentru memorarea tipului respectiv de data. De exemplu pentru memorarea unei date de tip caracter este necesar un singur bloc cu capacitatea de 1 byte. La scrierea programelor, si la introducerea de la tastatura/citirea de pe ecran a datelor in timpul executiei aplicatiei, programatorului/operatorului i-ar fi foarte dificil sa lucreze cu datele reprezentate in format binar. Este mult mai usor ca datele sa fie prezentate in aceasta etapa sub forma simbolica folosind cifre - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, litere – A, B, C, ... a, b, c, ... precum si alte semne - @, #, $, %, “, ?, !, ..., etc. Toate aceste simboluri folosite la scrierea programelor si reprezentarea datelor se numesc caractere si formeaza setul de caractere al calculatorului respectiv. Deoarece calculatorului nu poate memora si procesa decat date binare, aceste caractere sunt codate, fiecarui caracter fiindu-i asociat un cod binar, o combinatie unica de 1 si 0. La introducerea lor in calculator se face codarea sub forma binara iar la afisare sunt decodate, pe ecran afisandu-se simbolul corespunzator codului binar. Astfel cand se apasa pe tastatura o tasta avand inscriptionata pe ea simbolul 1, catre calculator este transmisa data 00110001, acesta fiind codul binar al cifrei 1. De asemenea cind un program trimite spre placa grafica a calculatorului codul binar 00110001, aceasta va determina afisarea pe display a simbolului 1. Limbajul Java foloseste pentru codarea caracterelor codul Unicode. Acest cod foloseste doi byte pentru reprezentarea codului. In acest cod, toate caracterele litere, cifre si semne (de pe tastatura ) contin in octetul superior 00000000.

230

CURS 19

Caracterele se pot folosi pentru introducerea/afisarea unor informatii (date) nestructurate cum ar fi textele unor documente. In acest caz informatia poate fi cel mult vazuta ca o succesiune de linii de text separate prin caracterul de control ‘\r’(00001101) care la afisare determina trecerea cursorului pe randul urmator. Pe de alta parte informatia poate fi memorata si sub o forma structurata constand dintr-o succesiune de “inregistrari” fiecare astfel de inregistrare fiind la randul sau impartita pe campuri. Un camp este un grup de caractere avand o semnificatie convenita. de exemplu un camp constand numai din litere poate avea semnificatia numelui unei persoane. De exemplu o inregistrare privind un anumit salariat al unei intreprinderi poate contine urmatoarele campuri: 1. Numar de legitimatie 2. Nume 3. Adresa 4. Salariu tarifar orar 5. Numar de ore lucrate 6. Salariul brut 7. Salariul net Pentru fiecare angajat al intreprinderii poate exista o astfel de inregistrare, campurile acesteia continand datele corespunzatoare angajatului respectiv. acest ansamblu de inregistrari constitue un fisier. Fisierul de personal al unei companii mici contine un numar mic de inregistrari ( de exemplu 30) dar fisierul unei companii mari poate atinge un numar de zeci de mii de astfel de date. In figura 19.1 este reprezentata ierarhizarea datelor descrisa mai sus.

Fig.19.1 Ierarhizarea datelor

PROGRAMARE IN JAVA - Note de curs

231

Pentru a usura cautarea in fisier a unei anumite inregistrari cel putin unul din campuri al inregistrarii se alege drept cheie de cautare. Campul cheie trebuie astfel ales incat sa identifice in mod unic inregistrarea cautata. Cheia de cautare poate sa fie de exemplu numarul de legitimatie al unui anumit angajat deoarece identifica in mod unic inregistrarea acestuia ( nu exista doi angajati cu acelasi numar de legitimatie). Exista mai multe moduri de a organiza inregistrarile in fisier. Un mod este de a inscrie inregistrarile intr-un fisier secvential, una dupa alta, in ordinea valorilor din campul cheie ales. De regula intreprinderile stocheaza informatiile privind activitatea lor in mai multe fisiere de date - date de personal, date privind stocurile, date privind situatia facturilor, date privind operatiile contabile, etc. Unele date sunt interdependente. Un grup de fisiere continand date interdependente astfel incat modificarea unor date dintr-un fisier implica modificarea datelor din restul de fisiere din grup formeaza o baza de date. Un pachet de programe destinat gestiunii fisierelor unei baze de date constitue un sistem de gestiune a bazelor de date (SGBD).

Clasa File si operatii cu fisiere
Pentru a efectua diferite operatii asupra unui fisier aplicatia trebuie sa stabileasca intai o legatura cu sistemul de operare care il gestioneaza fizic pe disc, prin creerea unei “interfete” cu serviciile oferite de acesta. Aceasta “interfata” este implementata de clasa File care defineste cate o metoda pentru fiecare operatie uzuala de gestiune a unui fisier. Atunci cand o astfel de metoda este apelata si executata de un fir de executie al aplicatiei, ea apeleaza la randul sau rutina corespunzatoare a sistemului de operare care la randul sau va efectua operatia dorita. Relatia aplicatie - sistem de operare – fisier este reprezentata schematic in figura 19.2.

Fig.19.2 - Relatia aplicatie - sistem de operare – fisier Threadul se va folosi de obiectul file ca de un instrument comandand operatiile asupra fisierului asa cum un operator coonduce de la pupitrul de comanda al unui furnal operatiile de obtinere a unei sarje de fonta. Aici operatorul este omologul threadului, pupitrul de comanda echivalentul obiectului File iar furnalul este echivalentul sistemului de operare. Utilizarea unei astfel de interfete asigura si independenta de platforma (hardware si sistem de operare). Pupitrul este o “cutie neagra” prevazuta cu

232

CURS 19

o interfata – butoane, manete, aparate indicatoare. Teoretic, pentru obtinerea unei sarje de fonta, acelasi operator, va putea da aceeasi secventa de comenzi de la un pupitru cu aceleasi butoane si aparate indicatoare si pentru un furnal american si pentru un furnal japonez. Conditia este ca semnalele de comanda generate de pupitru in urma apasarii butoanelor sa initieze corect procesele ce se desfasoara in furnal (hardware-ul pupitrului sa fie adaptat la tipul furnalului) La fel si clasa File este o “cutie neagra” metodele si variabilele sale fiind “interfata” clasei, butoanele manetele si aparatele indicatoare. Modul in care aceste metode sunt “cablate” in interiorul clasei difera de la un sistem de operare la altul dar operatiile asupra fisierului sunt aceleasi. Clasa File este o subclasa a clasei Object si face parte din pachetul java.io definind urmatoarele variabile si metode: ¾ final static String pathSeparator – string continand simbolul folosit pentru separarea cailor (PATH) (“;” in DOS si Windows) ¾ final static char pathSeparatorChar – caracterul folosit pentru separarea cailor (PATH) (“;” in DOS si Windows) ¾ final static String separator – string continand simbolul folosit pentru separarea numelor de directoare intr-o cale (“\” in DOS si Windows) ¾ final static char separator – caracterul folosit pentru separarea numelor de directoare intr-o cale (“\” in DOS si Windows) ¾ File(String path) – constructorul clasei. Are ca argument un string continand calea spre fisier. ¾ File(String dir, String nume) – constructorul clasei. Are ca argument un string continand numele directorului in care se afla fisierul si un alt string continand numele fisierului. ¾ File(String path, String nume) – constructorul clasei. Are ca argument un string continand calea spre fisier si un alt string continand numele fisierului. ¾ boolean canRead() – intoarce true daca programul poate citi din fisier. ¾ boolean canWrite() – intoarce true daca programul poate scrie in fisier. ¾ boolean delete() – Strege fisierul de pe disc. Intoarce true daca operatia a reusit. ¾ boolean equals(Object altObiect) – Compara obiectul this.File cu obiectul altObiect. Intoarce true daca altObiect este un obiect File avand aceeasi cale. ¾ boolean exists() – intoarce itrue daca fisierul exista. ¾ boolean delete() – Verifica daca fisierul exista pe disc. Intoarce true daca fisierul a fost gasit. ¾ String getAbsolutePath() - intoarce un string continand calea absoluta catre fisier (de la radacina). ¾ String getName() - intoarce un string continand numele fisierului. ¾ String getParent() - intoarce un string continand numele directorului parinte (toata calea mai putin numele fisierului). ¾ String getPath() - intoarce un string continand toata calea, inclusiv numele fisierului. ¾ int hashCode()- intoarce o valoare intreaga continand hash-code –ul fisierului calculat pe stringul continand calea. Este util in cautarea si identificarea rapida a acestuia fiind putin probabil ca doua fisiere sa aibe acelasi hash-cod. ¾ boolean isAbsolute() – intoarce true daca calea este absoluta. ¾ boolean isDirectory() – intoarce true daca obiectul descrie un director. ¾ boolean isFile() – intoarce true daca obiectul descrie un fisier. ¾ long lastModified() – intoarce o valoare fara semnificatie (similara cu hash-codul) calculata pe baza timpului de la ultima modificare. Se foloseste numai la compararea vechimii a doua fisiere.

PROGRAMARE IN JAVA - Note de curs

233

¾ long length() – intoarce dimensiunea fisierului in bytes. ¾ String[] list() – intoarce un tablou de stringuri continand lista numelor tuturor fisierelor din calea curenta. ¾ String[] list(Filenamefilter filter) – intoarce un tablou de stringuri continand lista numelor tuturor fisierelor din calea curenta care corespund cu criteriile de filtrare specificate de obiectul filter. ¾ boolean mkdir() – creaza directorul curent. Intoarce true daca operatia a reusit. ¾ boolean mkdirs() – creaza calea curenta. Intoarce true daca operatia a reusit. ¾ boolean renameTo(File newName) – redenumeste fisierul curent. Intoarce true daca operatia a reusit. ¾ String toString() – intoarce calea spre fisier.

Accesarea datelor din fisiere
Pentru efectuarea operatiilor de citire/scriere din/in fisiere limbajul Java prevede un mecanism bazat pe stream-uri. Astfel in cazul citirii de catre un thread a datelor dintrun fisier, acesta se va folosi de un obiect din clasa FileInputStream a carui sursa de date este fisierul respectiv (figura 19.3 a). In cazul scrierii de date, threadul se va folosi de un obiect din clasa FileOutputStream conectat la fisierul respectiv pe folosindu-l ca rezervor de date (figura 19.3 b).

Fig.19.3 Accesarea fisierelor Clasele FileInputStream si FileOutputStream prevazute in pachetul java.io sunt versiuni robuste, specializate in accesarea fisierelor, ale claselor InputStream si OutputStream. Aceste clase clase ofera numai o parte din metodele specificate de clasele InputStream si OutputStream permitand numai citirea respectiv scrierea din/in fisiere pe disc fara insa sa includa si metode de gestiune a streamurilor. Astfel clasa FileInputStream defineste urmatoarele metode: ¾ FileInputStream(File file) thows FileNotFoundException – constructor al unui stream de intrare conectat la fisierul specificat. ¾ FileInputStream(String name) thows FileNotFoundException – constructor al unui stream de intrare conectat la fisierul cu numele specificat. ¾ int avaiable() throws IOException – intoarce numarul de bytes disponibili. ¾ void close() throws IOException – inchide streamul si fisierul. ¾ protected void finalize() throws IOException – metoda callback apelata automat

*. } FileOutputStream out=new FileOutputStream(args[0]). class Copy{ public static void main(String[] args) throws IOException { if(args.println("Usage: Copy <src> <dest>"). System.out. Intoarce – 1 daca s-a atins sfarsitul de fisier. ¾ void write(int b) throws IOException – scrie byte-ul b in stream. Intrucat fisierul consola nu poate avea un sfarsit fizic. int len) throws IOException – scrie len octeti din tabloul de bytes b incepand cu indexul offset in stream. } FileInputStream in=new FileInputStream(args[0]).length==0){ System. int b. .length < 2){ System. ¾ int read(byte b[]) throws IOException – citeste in tabloul specificat ca argument bytes din stream. Programele urmatoare demonstreaza utilizarea streamurilor pentru crearea si acesarea fisierelor import java. ¾ void write(byte b[]. ¾ long skip(long num) ) throws IOException – extrage si ignora num octeti din stream.io. int len) throws IOException – citeste si inscrie incepand cu pozitia offset in tabloul specificat ca argument len bytes din stream. Programul se termina cand se detecteaza la citirea din streamul de intrare System.in) si ii depune intr-un fisier al carui nume este preluat din linia de comanda. ¾ void write(byte b[]) throws IOException – scrie tabloul de bytes b in stream. Intoarce numarul efectiv de octeti extrasi.in sfarsitul de fisier. class Con2File{ public static void main(String[] args) throws IOException { if(args. int offset. while((b=System.exit(0).in. import java. Intoarce numarul de bytes cititi sau –1 daca s-a atins sfarsitul de fisier.io. } } Programul de mai sus preia codurile caracterelor tastate la consola ( fisierul standard de intrare accesat print streamul System. ¾ int read(byte b[].exit(0).write(b). ¾ FileOutputStream(String name) thows IOException – constructor al unui stream de iesire conectat la fisierul specificat prin stringul name. ¾ void close() throws IOException – inchide streamul si fisierul. ¾ int read() throws IOException – citeste si intoarce un byte din stream.*. ¾ protected void finalize() throws IOException – metoda callback apelata automat inainte de distrugerea obiectului. int offset.out.println("Usage: Con2File <file_name>").read())!=-1)out.234 CURS 19 inainte de distrugerea obiectului. acesta easte semnalat prin tastarea combinatiei de taste <CTRL>Z. Intoarce numarul de bytes cititi sau –1 daca s-a atins sfarsitul de fisier. In clasa FileOutputStream sunt definite metodele urmatoare: ¾ FileOutputStream(File file) thows IOException – constructor al unui stream de iesire conectat la fisierul specificat prin file. System.

import java.flush().io. In figura 19.Note de curs FileOutputStream out=new FileOutputStream(args[1]).print((char)b).out. else System.read())!=-1)out. while(( b=in.print('\n').println("Usage: File2Con <file_name>"). System.out). int b. } System. . Numele celor doua fisiere sunt preluate din primele doua argumente ale liniei de comanda. int b.length==0){ System.out. El preia octetii din fisierul sursa al carui nume este preluat din primul argument al liniei de comanda si ii trimite la consola.read())!=-1){ if(b=='\r')System.out.out. while((b=in. } } Programul de mai sus realizeaza copierea unui fisier la consola (fisierul standard de iesire accesat prin streamul de iesire System.PROGRAMARE IN JAVA . class File2Con{ public static void main(String[] args) throws IOException { if(args.*.4 este prezentat listingul unor comenzi de executie a programelor de mai sus si a unor comenzi date sistemului de operare precum si rezultatelor afisate la consola in urma acestor comenzi. } } 235 Programul de mai sus realizeaza copierea unui fisier in alt fisier.write(b).exit(0). El preia octetii din fisierul sursa si ii depune intr-un fisier destinatie. } FileInputStream in=new FileInputStream(args[0]).

In momentul in care bufferul este plin.bufferizarea.19. Aceste streamuri sunt si ele de doua feluri – de intrare si de iesire fiind subclase ale claselor abstracte InputStream si OutputStream insa au ca sursa/rezervor de date streamuri primitive cum ar fi FileInputStream si FileOutputStream. Rolul acestor streamuri este de a perfectiona interfata de acces la date. Rezervorul de date in care sunt trimisi octetii din BufferedOutputStream este un obiect FileOutputStream (figura 19. Blocul de date este stocat intr-un buffer intern de unde acestea sunt preluate de thread octet cu octet la fiecare apel al metodei read().5b). . imediat ce se executa o citire dintr-un stream FileInputStream acesta este “golit” de byte-ul continut si un nou byte este adus automat din fisier in stream pregatindu-se o noua citire.5a). printr-o singura operatie de acces. sunt depuse intr-un buffer. clasa BufferedOutputStream implementeaza scrierea bufferizata a datelor. In momentul in care bufferul este golit. Fig. Similar. Similar. In loc ca streamul sa “incarce” cate un octet de la sursa. el incarca un bloc de octeti odata.19. iarasi printr-o singura operatie de acces.4 – Crearea si accesarea fisierelor Interconectarea streamurilor Am vazut ca streamurile FileInputStream si FileOutputStream nu implementeaza decat operatiile primitive de citire/scriere a unor date de tip byte din/in fisiere. Daca se doreste scrierea datelor din buffer inainte de umplerea acestuia se apeleaza metoda flush(). in cazul nostru un obiect FileInputStream (figura 19. Datele trimise de thread in loc sa fie directate direct spre destinatie. Sursa de date pentru BufferedInputStream poate fi orice stream subclasa a clasei abstracte InputStream. Pentru a putea folosi mecanisme mai evoluate de acces la date trebuie sa folosim streamuri care implementeaza aceste mecanisme.5 Filtrarea streamurilor Clasa BufferedInputStream implementeaza o proprietate importanta din punct de vedere al eficientei operatiilor de preluare a datelor de la sursa de date .236 CURS 19 Fig. Sa analizam de exemplu clasele BufferedInputStream si BufferedOutputStream. automat se efectueaza o reincarcare a sa prin aducerea unui nou bloc de bytes de la sursa de date. Imediat ce un byte de date este depus in streamul FileOutputStream el este scris in fisierul destinatie. intreg continutul su este trimis la destinatie. printr-o singura operatie de acces.

} } Streamurile bufferizate pot “interfata” si alte streamuri primitive de intrare/iesire cum ar fi cele din clasele ByteArrayInputStream/ByteArrayOutputStream sau StringBufferInputStream.Note de curs 237 La construirea unui obiect BufferedInputStream acesta este legat de un stream sursa de date – in cazul nostru un obiect din clasa FileInputStream specificat ca argument al unuia din constructorii clasei: ¾ BufferedInputStream(InputStream in) – se creaza un streeam de intrare bufferizat cu o dimensiune implicita a bufferului. while(( b=in.println("Usage: Copy <src> <dest>").read())!=-1)out. clasa defineste si urmatoarele variabile protejate: ¾ protected byte buf[] – referinta la bufferul de date. ¾ BufferedInputStream(InputStream in.limita maxima pana la care se poate avansa relativ la marcaj inainte ca acesta sa fie sters. Similar un stream BufferedOutputStream trebuie legat la un stream de iesire – in cazul nostru FileOutputStream . class Copy{ public static void main(String[] args) throws IOException { if(args. ¾ BufferedrOutputStream(OutputStream out. out.exit(0). Ea are constructorii: ¾ ByteArrayInputStream (byte buf[]) – se creaza un streeam de intrare care are ca sursa de date tabloul de bytes buf.*. import java. ¾ protected int count – numarul de octeti continut de buffer ¾ protected int marklimit . ¾ protected int pos – pozitia curenta in buffer. bazata pe utilizarea streamurilor cu bufferizare a programului Copy din exemplul precedent. } BufferedInputStream in=new BufferedInputStream( new FileInputStream(args[0])). int size) se creaza un streeam de iesire bufferizat cu o dimensiune size a bufferului. ¾ protected int count – numarul de octeti continut de buffer Programul urmator este o versiune modificata.write(b).io.out. int size) – se creaza un streeam de intrare bufferizat cu o dimensiune size a bufferului. BufferedOutputStream out=new BufferedOutputStream( new FileOutputStream(args[1])). Clasa ByteArrayInputStream este o subclasa a clasei abstracte InputStream care are ca sursa de date un tablou de octeti.PROGRAMARE IN JAVA . int b.length < 2){ System. Referinta la buffer este pastrata in variabila .specificat ca argument al constructorului clasei: ¾ BufferedrOutputStream(OutputStream out) se creaza un streeam de iesire bufferizat cu o dimensiune implicita a bufferului. System. clasa defineste si urmatoarele variabile protejate: ¾ protected byte buf[] – referinta la bufferul de date.flush(). ¾ protected int markpos – pozitia marcajului.

int offset. Referinta la buffer este pastrata in variabila protected byte buf[].238 CURS 19 protected byte buf[]. Pentru a citi/scrie din/in fisiere astfel de tipuri de date fluxul de octeti trebuie formatat. int length) – se creaza un streeam de intrare care are ca sursa de date tabloul de bytes buf. Interfata defineste urmatoarele DataInput metode: ¾ abstract boolean readBoolean() throws IOException – citeste din stream si intoarce o valoare de tip boolean. Variabilele protejate ale clasei protected int pos (indicand pozitia curenta) si respectiv protected int count (indicand numarul de bytes continuti de stream) sunt setate corespunzator. o valoare de tip int de exemplu trebuie dezasamblata in patru octeti ce vor fi trimisi apoi succesiv la destinatie. Citirea va incepe de la octetul cu indexul offset si va continua pana vor fi preluati length octeti dupa care se semnaleaza sfarsit de fisier. Limbajul prevede doua astfel de interfete – DataInput definind metode pentru citirea formatata a datelor si DataOutput pentru scrierea formatata a datelor. int length) – se creaza un streeam de intrare care are ca sursa de date tabloul de bytes buf. Variabilele protejate ale clasei protected int pos (indicand pozitia curenta) si respectiv protected int count (indicand numarul de bytes continuti de stream) sunt setate corespunzator. ¾ ByteArrayInputStream (byte buf[]. Clasa ByteArrayOutputStream este o subclasa a clasei abstracte InputStream care are ca “rezervor” de date un tablou de octeti. trebuie cititi patru octeti si asamblati impreuna pentru a obtine valoarea intreaga respectiva. Referinta la buffer este pastrata in variabila protected byte buf[]. La scriere operatia de formatare este inversa. etc. Referinta la buffer este pastrata in variabila protected String buffer. Referinta la buffer este pastrata in variabila protected byte buf[]. date de tip String. Citirea va incepe de la octetul cu indexul offset si va continua pana vor fi preluati length octeti dupa care se semnaleaza sfarsit de fisier. pentru a obtine un intreg. Clasa defineste si variabilele protejate protected int pos (indicand pozitia curenta in stream) si protected int count (indicand numarul de bytes continuti de stream) Formatarea datelor la accesul fisierelor Streamurile prezentate anterior ofera un acces primitiv la datele din fisiere. valori reale. int offset. ¾ abstract byte readByte() throws IOException – citeste din stream si intoarce o . Clasa StringBufferInputStream este o subclasa a clasei abstracte InputStream care are ca sursa de date un String. Ea are constructorii: ¾ ByteArrayInputStream (byte buf[]) – se creaza un streeam de intrare care are ca sursa de date tabloul de bytes buf. ¾ ByteArrayInputStream (byte buf[]. Ea are constructorul: ¾ StringBufferInputStream (String s) – se creaza un streeam de intrare care are ca sursa de date stringul s folosit ca buffer de octeti. Programele insa de regula luccreaza cu alte tipuri de date – intregi. extragand/inscriind octeti de date. Aceasta inseamna ca la citire. Pentru a putea citi/scrie date formatate un stream trebuie sa implementeze o interfata definind un pachet de metode publice specializate care sa realizeze “inpachetarea” octetilor cititi intr-un tip de date particular respectiv “despachetarea” la scriere a valorii de un tip particular in octetii componenti.

int len ) throws IOException – scrie in stream len octeti din bufferul b. ¾ abstract void writeByte(int v) throws IOException – scrie in stream un byte cu valoarea transmisa ca argument. ¾ abstract void writeChar(int v) throws IOException – scrie in stream o valoarea de tip char transmisa ca argument.int offset. abstract float readFloat() throws IOException – citeste din stream si intoarce o valoare de tip float. ¾ abstract void writeInt(int v) throws IOException – scrie in stream o valoarea de tip . abstract void readFully(byte b[]) throws IOException – citeste octeti din stream pana cand tabloul b de este completat in intregime. abstract int readInt() throws IOException – citeste din stream si intoarce o valoare de tip int.PROGRAMARE IN JAVA .int offset. abstract double readDouble() throws IOException – citeste din stream si intoarce o valoare de tip double.Note de curs ¾ ¾ ¾ ¾ ¾ ¾ ¾ ¾ ¾ ¾ ¾ ¾ 239 valoare de tip byte. ¾ abstract void writeBoolean(boolean v) throws IOException – scrie in stream o valoarea de tip boolean transmisa ca argument. ¾ abstract void writeDouble(double v) throws IOException – scrie in stream o valoarea de tip double transmisa ca argument. Interfata defineste urmatoarele DataOutput metode: ¾ abstract void write(byte b[]. abstract String readUTF () throws IOException – citeste din stream si intoarce un String in format UTF (Unicode). abstract int skipBytes (int num) throws IOException – “sare” peste cel mult num octeti din stream si intoarce numarul efectiv de octeti extrasi. abstract long readLong() throws IOException – citeste din stream si intoarce o valoare de tip long. ¾ abstract void writeFloat(float v) throws IOException – scrie in stream o valoarea de tip float transmisa ca argument. incepand cu elementul de la indexul offset. abstract int readUnsignedShort () throws IOException – citeste din stream si intoarce o valoare de tip unsigned short. abstract char readChar() throws IOException – citeste din stream si intoarce o valoare de tip char.int length) throws IOException – citeste octeti din stream pana cand tabloul b de este completat incepand cu pozitia offset cu un numar de length bytes. ¾ abstract void writeBytes(String s) throws IOException –scrie in stream octetii continuti de stringul s. ¾ abstract void write(int b ) throws IOException – scrie in stream o valoarea de tip int transmisa ca argument. abstract int readUnsignedByte () throws IOException – citeste din stream si intoarce o valoare de tip unsigned byte. abstract short readShort () throws IOException – citeste din stream si intoarce o valoare de tip short. ¾ abstract void write(byte b[] ) throws IOException – scrie in stream octetii continuti de bufferul b. abstract void readFully(byte b[]. ¾ abstract void writeChars(String s) throws IOException –scrie in stream caracterele continute de stringul s.

¾ final short readShort () throws IOException – citeste din stream 4 octeti si intoarce o valoare de tip short pe 32 de biti. ¾ abstract void writeLong(long v) throws IOException – scrie in stream o valoarea de tip long transmisa ca argument. ¾ final long readLong() throws IOException – citeste din stream 8 octeti si intoarce o valoare de tip long pe 64 de biti. ¾ final int read(byte b[]. Constructorul acestei clase este: ¾ public DataInputStream(InputStream in) – construieste un stream de intrare DataInputStream conectat la streamul de intrare in ca sursa de date. ¾ final int readInt() throws IOException – citeste din stream 4 octeti si intoarce o valoare de tip int pe 32 de biti. ¾ final boolean readBoolean() throws IOException – citeste din stream si intoarce o valoare de tip boolean. ¾ final byte readByte() throws IOException – citeste din stream si intoarce o valoare de tip byte. ¾ abstract void writeShort(int v) throws IOException – scrie in stream o valoarea de tip short transmisa ca argument. ¾ final double readDouble() throws IOException – citeste din stream 8 octeti si intoarce o valoare de tip double pe 64 de biti. perechea “\r\n” sau pana este detectat sfarsitul de fisier (EOF). ¾ final String readLine () throws IOException – citeste succesiv octeti din stream pana la primul caracter de control ‘\n’ sau ‘\r’. ¾ final int readUnsignedByte () throws IOException – citeste din stream si intoarce . ¾ abstract void writeUTF (String s) throws IOException – scrie in stream un String in format UTF (Unicode).int length) throws IOException – citeste un numar de length octeti din stream pana cand tabloul b incepand cu indexul offset. Implementarea interfetei DataInput este realizata de clasa DataInputStream care in plus extinde clasa FilterInputStream mostenind si toate metodele acesteia (o versiune non-abstracta a clasi InputStream). ¾ final float readFloat() throws IOException – citeste din stream 4 octeti si intoarce o valoare de tip float pe 32 de biti. ByteArrayInputStream. ¾ final void readFully(byte b[].int offset. Metoda intoarce numarul de octeti citit. ¾ final void readFully(byte b[]) throws IOException – citeste octeti din stream si nu revine pana cand tabloul b de este completat in intregime.240 CURS 19 int transmisa ca argument. StringBufferInputStream. ¾ final char readChar() throws IOException – citeste din stream 2 octeti si intoarce o valoare de tip char pe 16 biti. Acest stream poate fi oricare din streamurile de intrare primitive discutate (FileInputStream. PipedInputStream).int offset.int length) throws IOException – citeste octeti din stream si nu revine pana cand tabloul b nu este completat incepand cu pozitia offset cu un numar de length bytes. Clasa defineste metodele: ¾ final int read(byte b[]) throws IOException – citeste octeti din stream pana cand tabloul b si intoarce numarul de octeti citit. Intoarce un String continand caracterele respective.

¾ final void writeFloat(float v) throws IOException – scrie in stream o valoarea de tip float transmisa ca argument. Acest stream poate fi oricare din streamurile de intrare primitive discutate (FileOutputStream.PROGRAMARE IN JAVA . Implementarea interfetei DataOutputeste realizata de clasa DataOutputStream care in plus extinde clasa FilterOutputStream mostenind si toate metodele acesteia (o versiune non-abstracta a clasi OutputStream). ¾ final void writeDouble(double v) throws IOException – scrie in stream o valoarea de tip double transmisa ca argument. ¾ final void writeByte(int v) throws IOException – scrie in stream un byte cu valoarea transmisa ca argument. Constructorul acestei clase este: ¾ public DataOutputStream(OutputStream out) – construieste un stream de intrare DataOutputStream conectat la streamul de intrare out ca “rezervor” de date. . ¾ final void writeInt(int v) throws IOException – scrie in stream o valoarea de tip int transmisa ca argument. ByteArrayOutputStream.Note de curs 241 o valoare de tip unsigned byte. ¾ final void writeLong(long v) throws IOException – scrie in stream o valoarea de tip long transmisa ca argument. ¾ final void writeChar(int v) throws IOException – scrie in stream o valoarea de tip char transmisa ca argument. ¾ final void writeShort(int v) throws IOException – scrie in stream o valoarea de tip short transmisa ca argument. ¾ final void writeBoolean(boolean v) throws IOException – scrie in stream o valoarea de tip boolean transmisa ca argument. incepand cu elementul de la indexul offset. int len ) throws IOException – scrie in stream len octeti din bufferul b.. ¾ synchronized void write(int b ) throws IOException – scrie in stream o valoarea de tip int transmisa ca argument. PipedOutputStream). ¾ final int readUnsignedShort () throws IOException – citeste din stream 2 octeti si intoarce o valoare de tip unsigned short pe 16 biti. ¾ synchronized void write(byte b[]. ¾ final void writeChars(String s) throws IOException –scrie in stream caracterele continute de stringul s. ¾ final int skipBytes (int num) throws IOException – “sare” peste cel mult num octeti din stream si intoarce numarul efectiv de octeti extrasi.int offset. ¾ final String readUTF () throws IOException – citeste din stream si intoarce un String in format UTF (Unicode). ¾ final void writeBytes(String s) throws IOException –scrie in stream octetii continuti de stringul s. ¾ final void writeUTF (String s) throws IOException – scrie in stream un String in format UTF (Unicode). ¾ final int size() throws IOException – intoarce valoarea continuta de variabila written reprezentand numarul de octeti expediati. Clasa defineste variabila protected int written continand numarul de octeti inscrisi in stream si metodele: ¾ void flush() throws IOException – are ca efect golirea bufferului streamului la care este conectat (numai daca acesta este bufferizat).

System.out.out. class File2Con{ public static void main(String[] args) throws IOException { String s.out.println("Usage: File2Con <file_name>").exit(0).length==0){ System.println(s). if(args. El foloseste metoda readLine() a clasei DataInputStream pentru a citi linii de text din fisier intr-un string pe care il afiseaza apoi la consola: import java.242 CURS 19 Programul urmator este o versiune modificata.flush(). while((s=in. } DataInputStream in=new DataInputStream( new FileInputStream(args[0])).*.readLine())!=null){ System.io. } } } . System. bazata pe utilizarea streamurilor cu bufferizare a programului File2Con prezentat anterior.

Acest stream poate fi oricare din streamurile de intrare primitive discutate (FileOutputStream. . Daca parametrul autoflush are valoarea true bufferul va fi golit dupa fiecare linie de text transmisa (treminata cu caracterul de control ‘\n’).valueOf(o). ¾ void print(double d) – tipareste o valoare de tip double. ¾ synchronized void println(double d) – tipareste o valoare de tip double urmat de caracterul ‘\n’ (trece la linie noua). ByteArrayOutputStream. ¾ ¾ synchronized void println(boolean b) – tipareste o valoare de tip boolean urmat de caracterul ‘\n’ (trece la linie noua). ¾ synchronized void println(int i) – tipareste o valoare de tip int urmat de caracterul ‘\n’ (trece la linie noua). ¾ synchronized void print(String s) – tipareste toate caracterele continute de stringul s. ¾ void close() – inchide streamul. Acest stream poate fi oricare din streamurile de intrare primitive discutate (FileOutputStream. ¾ void flush() – goleste bufferul.intoarce true daca a aparut o eroare la scrierea datelor in stream. ¾ synchronized void println(long l) – tipareste o valoare de tip long urmat de caracterul ‘\n’ (trece la linie noua). boolean autoflush) – care construieste un obiect PrintStream conectat la un stream de iesire out ca destinatie a datelor. Clasa are doi constructori: ¾ PrintStream(OutputStream out) – care construieste un obiect PrintStream conectat la un stream de iesire out ca destinatie a datelor. PipedOutputStream).out deoarece obiectul System. ¾ synchronized void println(float f) – tipareste o valoare de tip float urmat de caracterul ‘\n’ (trece la linie noua). ¾ synchronized void print(char s[]) – tipareste toate caracterele continute de tabloul s.PROGRAMARE IN JAVA . ¾ void print(Object o) – tipareste valoarea intoarsa de metoda String. ¾ PrintStream(OutputStream out. Am folosit frecvent acest tip de stream de iesire apeland metodele lui System. ¾ void print(char c) – tipareste o valoare de tip char.Note de curs 243 Curs 20 Clasa PrintStream Aceasta clasa defineste un tip de stream de iesire derivat din FilterOutputStream destinat transmiterii de date sub forma de text. ByteArrayOutputStream. ¾ void print(long l) – tipareste o valoare de tip long. ¾ void print(int i) – tipareste o valoare de tip int. Metodele clasei sunt: ¾ boolean checkError() . PipedOutputStream). ¾ void print(float f) – tipareste o valoare de tip float.out este o instanta a clasei PrintStream. ¾ void print(boolean b) – tipareste o valoare de tip boolean.

lNume=new Label("Nume"). private GridBagLayout gbl.io. Programul are o interfata formata din patru campuri text in care se vor putea introduce informatiile respective si doua butoane – “Adaugare” care comanda adaugarea inregistrarii la fisier si “Terminare” care listeaza continutul fisierului la consola si termina executia programului. ¾ void write(byte b[].244 CURS 20 ¾ synchronized void println(char c) – tipareste o valoare de tip char urmat de caracterul ‘\n’ (trece la linie noua).awt. public Evidenta(){ super("Fisier secvential"). private DataOutputStream out. lPNume=new Label("Prenume"). .tGrupa.lNota. Fig. ¾ void write(int b ) – scrie un singur octet in stream. class Evidenta extends Frame{ private Label lNume.lGrupa. import java.tPNume. int len) – scrie in stream len octeti din bufferul b. private GridBagConstraints gbc.int offset.lPNume. ¾ synchronized void println(char s[]) – tipareste toate caracterele continute de tabloul s urmat de caracterul ‘\n’ (trece la linie noua). prenume.tNota. private Button bAdd. Interfata grafica este gestionata de un manager de amplasare GridBagLayout si este proiectata ca in figura 20.*.bTerm. Exemplu de creare a unui fisier cu acces secvential Programul urmator creeaza un fisier secvential format din inregistrari continand urmatoarele informatii despre studenti: nume. continutul campurilor de editare este sters.20. ¾ synchronized void println() .1.tipareste caracterul ‘\n’ (trece la linie noua). lGrupa=new Label("Grupa"). private TextField tNume. private String nume.*. Programul este urmatorul: import java. ¾ synchronized void println(String s) – tipareste toate caracterele continute de stringul s urmat de caracterul ‘\n’ (trece la linie noua). grupa si nota obtinuta.1 Proiectarea interfetei grafice Dupa fiecare adaugare. incepand cu elementul de la indexul offset.

gridheight=height. addComponent(tPNume. DataInputStream in=new DataInputStream( new FileInputStream("Studenti."). gbc.1. gbc=new GridBagConstraints(). gbc. } private void quit(){ try{ out.gbl.fill=gbc.1.BOTH. tNota=new TextField(2).id== Event.1.readUTF()+". .1.1. } public boolean handleEvent(Event e){ if(e.handleEvent(e). gbc. addComponent(bTerm.gbc.0.1.println(nume+". int height) 245 { gbc. } private void addComponent(Component c.1. gbc.0. gbc.gbc. bTerm=new Button("Terminare").2.gbl.1.gbc. addComponent(lNota.weightx=1.1).1.1).1).gridx=col. GridBagLayout gbl. addComponent(tNume.dat")).weighty=1.1).readUTF()+".3.2. GridBagConstraints gbc. while((nume=in. tNume=new TextField(20).setConstraints(c.weightx=1. addComponent(tGrupa. gbc.1.gbc. gbl. show().gridwidth=width.1).gbl.1).1.readUTF())!=null){ System. "+in. addComponent(lNume. addComponent(bAdd.NONE.EAST. resize(300.gbl.1.0.gbl.out. gbc.gbl.readInt()+".1). return true.gbl. setLayout(gbl=new GridBagLayout()). gbc.PROGRAMARE IN JAVA . gbc.close().150).gbc.gbl.gbc). addComponent(lPNume. "+in. tGrupa=new TextField(4). gbc.gbc.0. "+ in.gbc. addComponent(lGrupa. bAdd=new Button("Adaugare").gbc. add(c).1.1). addComponent(tNota.1).gbl.fill=gbc.1. tPNume=new TextField(20).gbc.HORIZONTAL.0. } return super.0.1).0. int width.weightx=2.weightx=2.gbc.fill=gbc.1.1.4.gridy=row. int row.Note de curs lNota=new Label("Nota").WINDOW_DESTROY){ quit().1.4.3. gbc.gbl. gbc.anchor=gbc. int col.

Din acest motiv operatia de adaugare/modificare de inregistrari intr-un fisier secvential este destul de greoaie.out=new DataOutputStream( new FileOutputStream("Studenti.setText(""). CURS 20 } public boolean action(Event e.dat . System. else if(e. out. out. hide().writeUTF(tPNume.dat. } public static void main(String[] args)throws IOException { Evidenta e=new Evidenta().setText("").dat . out.getText()). .setText("").getText())).old se copiaza in fisierul Studenti. } catch(Exception ex){} dispose(). e.writeUTF(tNume.Inregistrarile din fisierul Studenti. tNume.Se continua programul prin adaugarea de noi inregistrari.Fisierul existent Studenti.writeInt(Integer. Interfata grafica si rezultatele afisate de program sunt prezentate in figura 20.class Actualizarea fisierelor secventiale Prin operatia de deschidere a unui fisier acesta daca nu exista este creat si apoi deschis iar daca exista deja.2.Se creaza si se deschide un nou fisier Studenti. cel existent anterior fiind sters.getText()).old .getText()). } } El creaza si afiseaza fisierul Studenti. este deschis dar toate datele din el sunt sterse.exit(0). Fig.tNota.parseInt(tNota.close(). } catch(Exception ex){} } return true. tPNume. Object o){ if(e.writeUTF(tGrupa.20. Daca se doreste adaugarea de noi inregistrari la fisierul creat la executia precedenta programul ar trebui modificat astfel: .246 } in.setText("").dat .target==bAdd){ try{ out.dat trebuie redenumit in fisierul Studenti. tGrupa.dat")).target==bTerm) quit().2 – Interfata grafica si rezultatele afisate de programul Evidenta. Programul din exemplul precedent crea la fiecare executie un alt fisier Studenti.

read())!=-1) e. Toate aceste operatii ca si operatia de cautare a unei anume inregistrari din fisier. Insertia unei noi inregistrari intr-o anumita pozitie in fisier presupune de asemenea copierea intr-un nou fisier a tuturor inregistrarilor ce preced pozitia de insertie.dat"). class Evidenta extends Frame{ //.PROGRAMARE IN JAVA ..dat”.*. ceva mai complicat stau lucrurile daca se doreste stergerea sau modificarea unei inregistrari.dat" // in "Studenti.dat nu exista il creaza iar daca exista adauga noi inregistrari in fisier la inregistrarile deja existente.write(b). renameTo() si delete() definite in clasa File pentru a determina daca fisierul “Studenti.out=new DataOutputStream( new FileOutputStream("Studenti. Modificarea unei inregistrari presupune copierea intr-un nou fisier a tuturor inregistrarilor precedente inregistrarii modificate.. File f=new File("Studenti.out. Aceste inconveniente ce apar in cazul . adaugarea noii inregistrari si copierea in continuare a restului de inregistrari din fisierul original.// inchide “Studenti. pentru redenumirea lui in “Studenti.old").old" }else// Deschide un nou fisier "Studenti.dat")).close().dat" exista f. Aceasta poate deveni un impediment serios in cazul realizarii unor sisteme de tranzactionare in timp real (cum ar fi de exemplu cel de rezervare a locurilor) in care raspunsul la interogarea bazei de date trebuie sa fie dat intr-un timp rezonabil de scurt. Evidenta e=new Evidenta().//Destinatie while((b=in.old” o.java” exista. o=new File("Studenti. if(f.io.dat" e. } } In acest program am folosit metodele exists().awt.// redenumeste "Studenti.Note de curs 247 Programul urmator este o versiune modificata a programului anterior care daca fisierul Studenti. presupun citirea tuturor inregistrarilor precedente ceea ce poate deveni o operatie mare consumatoare de timp daca numarul de inregistrari din fisier este mare (de ordinul sutelor de mii sau chiar milioanelor)..old" DataInputStream in=new DataInputStream( new FileInputStream(o)). Stergerea unei inregistrari presupune crearea unui nou fisier in care sa se copieze toate inregistrarile dinantea si de dupa inregistrarea ce trebuieste eliminata.//copiere in.dat")). public static void main(String[] args)throws IOException { int b.*.//Sursa e.delete(). Variabile si metode identice cu cele dinprogramul precedent .out=new DataOutputStream( new FileOutputStream("Studenti.renameTo(o). adaugarea la acest fisier a inregistrarii modificate si copierea restului de inregistrari din fisierul vechi in fisierul nou. import java.exists()){ //"Studenti.old” si in final stergerea sa dupa efectuarea copierii din “Studenti.. Modificarile afecteaza doar metoda main() astfel: import java.//Sterge "Studenti.old” in noul fisier “Studenti.

de exemplu aplicatiile bancare sau cele de rezervare automata a locurilor. Folosind inregistrari de lungime fixa. Un fisier Java cu acces aleator este ca un tren cu mai multe vagoane (Figura 20. Aceasta este de fapt un stream “duplex”. In plus clasa permite. Pe masura ce octetii sunt cititi. Fig. sau in modul read/write – citire si scriere. 4 octeti sunt preluati de stream incepand cu cel aflat la deplasamentul indicat de pointerul de pozitie. specificarea modului de acces la fisier. Unele vagoane sunt incarcate. avansand pe urmatorul octet.3 – Fisier cu acces aleator Un fisier cu acces aleator poate fi creat si exploatat de un program Java cu ajutorul clasei RandomAccessFile. Limbajul Java nu impune o anumita structura pentru fisiere. In aceste cazuri programul trebuie sa proceseze tranzactia (depunerea/extragerea de numerar in/din contul clientului respectiv cautarea unui loc liber si inregistrarea rezervarii acestuia) intr-un fisier de date de dimensiuni mari intr-un timp acceptabil pentru utilizator (de ordinul secundelor).248 CURS 20 utilzarii fisierelor cu acces secvential pot fi evitate daca se folosesc fisiere cu acces aleator. Cand se efectueaza citirea unei valori int din fisier.3). fara a citi in prealabil toate inregistrarile ce o preced (ca in cazul fisierelor secventiale). Datele pot fi insertate in fisier fara a distruge informatia deja continuta de acesta.20. implementand ambele interfete DataInput si DataOutput. citirea/scrierea datele se face intr-o locatie aflata la un deplasament relativ la inceputul fisierului indicat de pointerul de pozitie in fisier. La scrierea in stream a unei valori de tip double. Asa cum vom vedea in continuare. Fisiere cu acces aleator Fisierele cu acces aleator sunt utilizate in cazul aplicatiilor in care timpul de acces la informatie este critic – asa cum sunt aplicatiile cu tranzactii in timp real. fisierul poate fi deschis in modul read-only – numai pentru citire. altele nu. aceasta este despachetata in cei 8 octeti componenti care sunt inscrisi succesiv in locatia din fisier aflata la deplasamentul indicat de pointerul de pozitie. poiterul este incrementat cu 1. la deschiderea fisierului. cunoasterea acestui deplasament permite accesul imediat la inregistrarea cautata. Dupa scrierea fiecarui . Streamul defineste metodele de scriere/citire formatata din fisier specificate de acestea. De asemenea informatia existenta in fisier poate fi actualizata sau stearsa fara a fi necesara rescrierea intregului fisier ca in cazul fisierelor cu acces secvential. poate calcula cu usurinta deplasamentul inregistrarii cautate aceasta fiind dependenta de valoarea campului cheie al inregistrarii si de lungimea inregistrarii. Cea mai simpla dintre aceste tehnici presupune utilizarea unor inregistrari avand toate aceeasi lungime. astfel incat programul trebuie efectiv sa creeze un fisier cu acces aleator implementand una dintr-o varietate mare de tehnici posibile. In momentul in care acest stream este conectat la un fisier.

PROGRAMARE IN JAVA . ¾ long getFilePointer() throws IOException – intoarce valoarea curenta a pointerului de pozitie in fisier (deplasamentul in octeti relativ la inceputul fisierului pe care este pozitionat pointerul de pozitie). String mode) throws IOException – creaza streamul si deschide fisierul specificat de file in modul de aces read-only daca parametrul mode este “r” sau red/write daca este “rw”.. ¾ int read(byte b[]) throws IOException – citeste octeti din stream pana cand tabloul b si intoarce numarul de octeti citit.int offset.int length) throws IOException – citeste un numar de length octeti din stream pana cand tabloul b incepand cu indexul offset. ¾ void close() – inchide fisierul. Metoda intoarce numarul de octeti citit. ¾ int read(byte b[]. ¾ final void readFully(byte b[]. ¾ final int readUnsignedByte () throws IOException – citeste din stream si intoarce o valoare de tip unsigned byte.int offset. ¾ final float readFloat() throws IOException – citeste din stream 4 octeti si intoarce o valoare de tip float pe 32 de biti. ¾ final int readInt() throws IOException – citeste din stream 4 octeti si intoarce o valoare de tip int pe 32 de biti. ¾ long length() throws IOException – intoarce dimensiunea in octeti a fisierului.Note de curs 249 octet. ¾ final long readLong() throws IOException – citeste din stream 8 octeti si intoarce o valoare de tip long pe 64 de biti.int length) throws IOException – citeste octeti din stream si nu revine pana cand tabloul b nu este completat incepand cu pozitia offset cu un numar de length bytes. ¾ int read() throws IOException – citeste si intoarce un singur byte. ¾ final char readChar() throws IOException – citeste din stream 2 octeti si intoarce o valoare de tip char pe 16 biti. pointerul este incrementat cu 1. perechea “\r\n” sau pana este detectat sfarsitul de fisier (EOF). ¾ final double readDouble() throws IOException – citeste din stream 8 octeti si intoarce o valoare de tip double pe 64 de biti. trecand pe pozitia urmatoare pentru o noua scriere. Metodele definite de clasa RandomAccessFile sunt: ¾ RandomAccessFile(File file. Intoarce un String continand caracterele respective. ¾ final byte readByte() throws IOException – citeste din stream si intoarce o valoare de tip byte. ¾ final int readUnsignedShort () throws IOException – citeste din stream 2 octeti si intoarce o valoare de tip unsigned short pe 16 biti. ¾ final short readShort () throws IOException – citeste din stream 4 octeti si intoarce o valoare de tip short pe 32 de biti. . String mode) throws IOException – creaza streamul si deschide fisierul cu numele specificat de stringul file in modul de aces read-only daca parametrul mode este “r” sau red/write daca este “rw”. ¾ final void readFully(byte b[]) throws IOException – citeste octeti din stream si nu revine pana cand tabloul b de este completat in intregime. ¾ RandomAccessFile(String file. pana cand toti octetii au fost inscrisi. ¾ final boolean readBoolean() throws IOException – citeste din stream si intoarce o valoare de tip boolean. ¾ final String readLine () throws IOException – citeste succesiv octeti din stream pana la primul caracter de control ‘\n’ sau ‘\r’.

¾ final void writeChars(String s) throws IOException –scrie in stream caracterele continute de stringul s. fie daca este un utilizator nou. ¾ void seek(long pos) throws IOException – pozitioneaza pointerul pe pozitia pos.4. ¾ final void writeShort(int v) throws IOException – scrie in stream o valoarea de tip short transmisa ca argument. ¾ final void writeInt(int v) throws IOException – scrie in stream o valoarea de tip int transmisa ca argument. ¾ void write(byte b[] ) throws IOException – scrie in stream octetii din bufferul b. ¾ final void writeBytes(String s) throws IOException –scrie in stream octetii continuti de stringul s. ¾ final int skipBytes (int num) throws IOException – “sare” peste cel mult num octeti din stream si intoarce numarul efectiv de octeti extrasi. va contine etichete.int offset. . campurile de text pentru afisarea unor mesaje. afisat la lansarea in executie a programului. Programul va tine pentru fiecare utilizator evidenta numarului de sesiuni de lucru efectuate. ¾ void write(byte b[]. reset si deschidere de cont nou acestea fiind amplasate ca in figura 20. Exemplu de utilizare a fisierelor cu acces aleator Programul urmator va implementa un mecanism de acces cu parola a unor utilizatori multipli. Prmul panou (gestionat de un GridBagLayout manager). ¾ final void writeLong(long v) throws IOException – scrie in stream o valoarea de tip long transmisa ca argument. La inceperea executiei. ¾ final void writeChar(int v) throws IOException – scrie in stream o valoarea de tip char transmisa ca argument. La inceperea unei sesiuni programul va afisa un mesaj de salut pentru userul respectiv. incepand cu elementul de la indexul offset. sa-si creeze contul inregistrandu-se in baza de date. programul va permite utilizatorului fie sa isi introduca numele de user si parola pentru acces. ¾ final void writeDouble(double v) throws IOException – scrie in stream o valoarea de tip double transmisa ca argument. int len ) throws IOException – scrie in stream len octeti din bufferul b. ¾ final void writeUTF (String s) throws IOException – scrie in stream un String in format UTF (Unicode). ¾ final void writeFloat(float v) throws IOException – scrie in stream o valoarea de tip float transmisa ca argument. ¾ final void writeBoolean(boolean v) throws IOException – scrie in stream o valoarea de tip boolean transmisa ca argument. Proiectarea interfetei grafice: Interfata grafica va consta dintr-o fereastra din clasa Frame continand doua “panouri” suprapuse (folosind CardLayout managerul).250 CURS 20 ¾ final String readUTF () throws IOException – citeste din stream si intoarce un String in format UTF (Unicode). introducerea numelui de user si a parolei precum si butoanele de confirmare. renuntare. ¾ final void writeByte(int v) throws IOException – scrie in stream un byte cu valoarea transmisa ca argument. Fiecare utilizator va fi inregistrat intr-o baza de date cu un nume de user si o parola. 1.

20. Fig. a numelui de user ales a parolei si a parolei repetate (pentru evitarea unei tastari gresite) si afisare de mesaje.1 al interfetei grafice Daca este actionat butonul bNew va fi creata si afisata o fereastra de dialog in cre utilizatorul va introduce informatiile necesare deschiderii unui cont nou. un buton “Ok”. toate controalele din panoul nr. un buton “Reset” si un buton “Cancel”.5.Note de curs 251 Fig.20.4 – Amplasarea controalelor in panoul nr. campuri text pentru introducerea numelui utilizatorului. La actionarea butonului bOk informatiile din fereastra de dialog vor fi citite.1 vor fi dezactivate. validate si inscrise sub forma de inregistrare in fisierul bazei de date. Fereastra de dialog va fi modala si va contine etichete. Amplasarea acestor controale in fereastra de dialog va fi gestionata de un GridBagLayout manager ca in figura 20.PROGRAMARE IN JAVA .5 – Amplasarea controalelor in fereastra de dialog a interfetei grafice Pe perioada cat fereastra de dialog este afisata. Cel de al doilea panou (gestionat de managerul implicit BorderLayout) va contine un .

Am fi putut sa inscriem in acest camp numele de user ales de utilizator dar aceasta ar fi implicat la cautarea in fisier a informatiei despre un anumit user compararea octet cu octet a unor stringuri. Fisierul usr. 2.ndx si usr. La lansarea programului “Canvas”-ul nu are nimic desenat pe suprafata sa.dat( deplasamentul acestei informatii relativ la inceputul fisierului). Proiectarea bazei de date Baza de date de tip relational va fi formata din doua fisiere: usr.20. am preferat ca pe baza primelor maxim opt caractere ale numelui userului sa formam un intreg lung reprezentat pe 8 bytes. Identificatorul se calculeaza ca fiind intregul lung avand ca reprezentare in memorie aceiasi 8 octeti care compun si stringul.252 CURS 20 control Canvas amplasat in centru pe care vor fi desenate informatiile specificate in formularea problemei si un buton “Terminare”.6. amplasat la “sud”. . deci printr-o singura instructiune masina. fiind mult mai rapida decat compararea a doua siruri de 8 octeti fiecare.dat. Din acest motiv. Desenarea se face numai la deschiderea unei sesiuni noi.dat este reprezentata in figura 20. actionarea caruia duce la incheierea sesiunii de lucru si revenirea la panoul 1.ndx si cele din fisierul usr. O astfel de inregistrare are doua campuri id si ndx continand primul un intreg lung reprezentand identificatorul utilizatorului (campul cheie) iar al doilea un intreg lung reprezentand pointerul catre informatia despre utilizatorul respectiv in fisierul usr. Reprezentarea si formula de calcul pentru stringul de 8 caractere “ABCDEFGH” a acestui identificator este exemplificata in figura 20. Structura bazei de date si relatia intre inregistrarile din fisierul usr.dat contine informatia privind utilizatorii inregistrati in baza de date.6 – Structura bazei de date 3.ndx este un fisier index iar fisierul usr. Operatia de comparare a intregilor se face prin scadere.ndx are inregistrari de lungime fixa de 16 bytes. Fisierul usr.ndx trebuie sa identifice in mod unic utilizatorul.7. operatie consumatoare de timp. Fig. Calculul identificatorului Valoarea intreaga din campul id al unei inregistrari din usr. Astfel codul literei A va fi octetul cel mai semnificativ al intregului (octetul 7) iar codul literei H va fi octetul cel mai putin semnificativ (octetul 0).

i++)b[i]=0.PROGRAMARE IN JAVA .getBytes(0.Note de curs 253 Fig.out. } public static void main(String[] args){ if(args.0). Cheia de criptare este formata din mai multe cifre fiecare din acestea fiind folosita ciclic la criptarea unui caracter. Am ales un algoritmul de criptare foarte simplu bazat pe shift-are codului fiecarui caracter cu o valoare intreaga cuprinsa intre 1 si 9 aceasta fiind una din cifrele cheii de criptare. .i<8.b. } return id. } System.println("User ID: "+ getID(args[0])). int len=s.length==0){ System. System. Cifrul ales pentru criptarea parolelor este 123.dat aceasta trebuieste criptata inainte de a fi inscrisa in fisier.out.i++){ id *=256.i<8.b.length(). long id=0. Mecanismul de criptare este descris in figura 20.9.len. for(i=0. Criptarea parolei Pentru ca parola unui utilizator sa ramana secreta chiar si pentru cineva care are acces la fisierul de date usr.7. } } Listingul din figura 20.println("Usage:UsrID <username>").8 arata rezultatul afisat de program pentru argumentul ABCDEFGH in linia de comanda.exit(0). for(i=len. id +=b[i].getBytes(0.7 Calculul identificatorului utilizatorului Metoda getID() din programul urmator implementeaza algoritmul de calcul al acestui identificator: class UsrID{ private static long getID(String s){ byte b[]=new byte[8]. }else s.8 Calculul identificatorului utilizatorului ABCDEFGH 4. Fig.20. if(len<8){ s.i.20.0).

getBytes(0.i++)b[i]=(byte)(b[i]+ i%3 + 1).20. Fig.i<b.length==0){ System.exit(0).out.out.b. for(int i=0.length()].20.length. } System.10 Criptarea parolei ABCDEFGH cu cifrul 123 . System.println("Usage:Password <password>").10 arata rezultatul afisat de program pentru argumentul ABCDEFGH in linia de comanda. return new String(b.b. } } Listingul din figura 20.0).254 CURS 20 Fig. s.println("Encripted password: "+ encrypt(args[0])).9 Algoritmul de criptare al parolei ABCDEFGH cu cifrul 123 Metoda encrypt() din programul urmator implementeaza acest algoritmul de criptare al parolei: class Password{ private static String encrypt(String s){ byte b[]=new byte[s. } public static void main(String[] args){ if(args.length.0).

aplicand asupra stringului referit de usr algoritmul prezentat la punctul 3. Se verifica daca stringul nu este vid. Daca este vid se afiseaza un mesaj de eroare in campul tMsg. 6.ndx si se citesc succesiv inregistrarile din acesta in variabilele long id si long pos. Daca cele doua valori sunt egale inseamna ca deja exista un utilizator cu acest nume. Daca ele nu sunt identice se afiseaza un mesaj de eroare in campul tMsg.Note de curs 255 Curs 21 Exemplu de utilizare a fisierelor cu acces aleator (continuare) 5. Daca numele utilizatorului este valid se continua cu validarea celor doua stringuri introduse ca parola in campurile tPsw1 si tPsw2. Algoritmul de autentificare a utilizatorului Dupa completarea campurilor text din fereastra de dialog cu informatiile necesare si actionarea butonului “Ok” programul va face intai validarea numelui utilizatorului prin preluarea in variabila String usr a sirului din campul tUsr. Daca este vid se afiseaza un mesaj de eroare in campul tMsg. Daca numele utilizatorului nu este vid se genereaza identificatorul utilizatorului. Daca sunt identice parola din campul tPsw1 va fi criptata aplicandu-i algoritmul prezentat la punctul 4 si memorata intr-o variabila String psw. Se verifica daca stringul nu este vid. Daca dupa o citire variabilele id si usrID sunt egale . Valoarea astfel obtinuta este memorata in variabila long usrID.dat si se inscrie lungimea acestuia (obtinuta apeland metoda length()) in fisierul usr. Dupa fiecare citire se compara valoarea din id cu valoarea din usrID.dat. Algoritmul de inregistrare a unui utilizator nou in baza de date Dupa completarea campurilor text din fereastra de dialog cu informatiile necesare si actionarea butonului “Ok” programul va face intai validarea numelui utilizatorului prin preluarea in variabila String usrName a sirului din campul tName. Se preia in variabila usr stringul din campul tUsr. Se deschide/creaza fisierul cu acces aleator usr. Daca numele de user nu este vid se genereaza identificatorul utilizatorului.PROGRAMARE IN JAVA . Dca se ajunge la sfarsitul fisierului fara ca sa fie gasita o inregistrare al carei cheie sa se potriveasca cu identificatorul utilizatorului se afiseaza un mesaj de eroare corespunzator in campul tMsg. Ca urmare se inchide fisierul si se afiseaza un mesaj de eroare in campul tMsg. Se deschide fisierul cu acces aleator usr.ndx si se citesc succesiv inregistrarile din acesta in variabilele long id si long pos. Se deschide fisierul cu acces aleator usr.dat la sfarsitul acestuia (apeland metoda seek()) si se inscriu pe rand informatiile privind utilizatorul continute de variabilele usrName. Valoarea astfel obtinuta este memorata in variabila long usrID. aplicand asupra sa algoritmul prezentat la punctul 3.ndx ca pointer la noua inregistrare ce va fi facuta in usr. Daca se ajunge la sfarsitul fisierului fara a gasi un identificator egal cu cel din variabila usrID inseamna ca numele de user ales este valid si se scrie in fisier valoarea din usrID. usr. Se verifica daca stringul nu este vid. Dupa fiecare citire se compara valoarea din id cu valoarea din usrID. usrID si se initializeaza contorul de sesiuni de lucru ale utilizatorului inscriind in fisier (int) 0. Daca este vid se afiseaza un mesaj de eroare in campul tMsg. Se pozitioneaza pointerul in fisierul usr. Se inchid fisierele bazei de date si fereastra de dialog.

Parola din campul tPsw se cripteaza intr-o variabila String usrPsw aplicandu-i algoritmul prezentat la punctul 4.dat a intregii inregistrari in variabilele String usrName. In continuare aplicatia va astepta actionarea butonului “Terminare”. Structura obtinuta a aplicatiei este redata in figura 21. flagul este readus pe pozitia false. String psw. Se deschide fisierul cu acces aleator usr. Daca acesta are valoarea true metoda paint() va “redesena” informatiile despre user pe suprafata canvas-ului. Proiectarea structurii aplicatiei In aceasta etapa se determina clasele de obiecte care sa implementeze interfetele grafice si algoritmii stabiliti la pasii anteriori. Se inchid fisierele bazei de date. Se obtine in variabila long pos pozitia curenta in fisier apeland metoda getFilePointer() si se decrementeaza cu 4 (lungimea unei date de tip int). Algoritmul de desfasurare al unei sesiuni de lucru Se citeste din fisierul usr. Daca cele doua siruri sunt egale deschiderea sesiunii este acceptata. Se pozitioneaza flagul boolean sesiune in true. 8.dat si se pozitioneaza pointerul din acest fisier pe pozitia pos (apeland metoda seek()). La semnalarea acestui eveniment. String usr. Acest flag este testat de metoda paint() ori de cate ori este apelata. Se scrie in fisier valoarea continuta de cnt.dat valoarea contorului de sesiuni in variabila int cnt. Dupa setarea flagului se apeleaza metoda repaint() care va determina executia metodei paint() si se face vizibil panoul 2 aducandul in varful stivei peste panoul 1.1 – structura aplicatiei RAFTest In diagrama de structura din aceasta figura sunt puse in evidenta legaturile dintre . Se da inapoi pointerul cu 4 octeti pentru a putea inscrie noua valoare a contorului apeland metoda seek(pos).21.1. 7. Se incrementeaza cnt.256 CURS 21 inseamna ca utilizatorul cu numele respectiv exista in baza de date. Se compara la egalitate sirurile referite de psw si usrPsw. de asemenea trebuiesc stabilite interconexiunile functionale intre obiectele din clasele de mai sus care vor intra in componenta aplicatiei. Se continua cu citirea din fisierul usr. panoul 2 este “ascuns” sub panoul 1 si se asteapta deschiderea unei noi sesiuni sau inregistrarea unui nou utilizator. In caz contrar nu deseneaza nimic. Fig.

folosind metoda addComponent() definita si utilizata in unele exemple anterioare. Controalele vor fi adaugate la panou conform proiectului. Daca butonul actionat este bRst se sterg informatiile din campurile text ale panoului. tPsw1. Daca se actioneaza butonul bQuit se termina aplicatia. tPsw2. Ea va inscrie in campul tMsg mesajul de eroare corespunzator. Daca autentificarea a reusit se sterg informatiile din campurile text ale panoului se se deschide sesiunea de lucru apeland metoda startSesiune()a clasei Panel2. bQuit din figura 20. Pentru comanda managerului de amplasare este prevazuta metoda public void showPanel(int panelNr) care va aduce in varful stivei formate din cele doua panouri pe cel indicat de argument. Daca butonul actionat este bRst se sterg informatiile din campurile text ale panoului. Daca se actioneaza butonul bCancel controalele ferestrei parinte sunt reactivate iar fereastra de dialog este inchisa. Va fi redefinita metoda action() astfel incat sa trateze evenimentele generate de butoane. Campul text tMsg va fi setat read-only. bOk. Daca butonul actionat este bOk se va apela metoda private boolean addUser() care implementeaza procedura de inregistrare a utizatorului descrisa la punctul 5. bCancel din figura 20. Daca butonul actionat este bOk se va incepe procedura de autentificare a utizatorului descrisa la punctul 6. ¾ Clasa Panel1 defineste variabila membru Panel2 p2. Constructorul clasei Panel1 va initializa referinta p2 cu o valoare primita ca argument. ¾ Clasa NewUserDialog este derivata din clasa Dialog. tUsr. bNew. Constructorul clasei NewUserDialog() va seta textul din bara de titlu a ferestrei. Va fi redefinita metoda action() astfel incat sa trateze evenimentele generate de butoane. ¾ Clasa Panel2 defineste variabilele String usr. Metoda intoarce true daca inregistrarea a decurs corect sau false daca a esuat.Note de curs 257 obiecte componente ale aplicatiei apartinand unor clase a caror descriere este data in continuare: ¾ Clasa principala RAFTest care contine metoda main() va fi derivata din clasa Frame. va dezactiva controalele ferestrei parinte. tPsw. lUsr. int cnt si boolean sesiune al carei rol a fost discutat la punctul anterior. tMsg si butoanele. va crea cele doua panouri Panel1 p1=new Panel1() si Panel2 p2=new Panel2(). Metoda statica main() va crea fereastra aplicatiei RAFTest wnd=new RAFTest() la creere. bRst. Va fi creat un manager de amplasare GridBagLayout dLayout cu obiectul asociat GridbagConstraints gbc. Constructorul clasei Panel2 va crea un obiect . va redimensiona si va face vizibila fereastra.5. va crea un manager de amplasare CardLayout mainLayout=new CardLayout(). constructorul clasei RAFTest() va seta textul din bara de titlu. le va adauga ferestrei. lPsw2 campurile text tName. Daca metoda intoarce true controalele ferestrei parinte sunt reactivate iar fereastra de dialog este inchisa. Va crea etichetele lUsr. lPsw1. Va fi creat managerul de amplasare GridBagLayout pLayout cu obiectul asociat GridbagConstraints gbc. il va seta ca manager de amplasare a ferestrei principale. tMsg si butoanele. bRst. Daca butonul actionat este bNew se trece la procedura de inregistrare a unui user prin creerea unei fereastre de dialog NewUserDialog dlg= NewUserDialog ().4. va crea etichetele lName.PROGRAMARE IN JAVA . bNew. Controalele vor fi adaugate la panou conform proiectului. folosind metoda addComponent() definita si utilizata in unele exemple anterioare. Campul text tMsg va fi setat read-only. lPwd campurile text tUsr.

public RAFTest(){//Constructorul clasei super("Random Access File Demo"). Implementare Mai jos este redat listingul complet al programului care implementeaza clasele proiectate la punctul precedent: import java.// procesarea celorlalte evenimente } public void quit(){//inchiderea fereastrei si terminarea // aplicatiei if(canClose){// daca terminarea aplicatiei este autorizata hide(). private Panel1 p1. ¾ Clasa Display extends Canvas redefineste metoda paint() astfel aceasta ori de cate ori este apelata sa testeze starea flagului sesiune a clasei parinte apeland metoda isSesiune() a acesteia.p2). private CardLayout mainLayout. show().258 CURS 21 Display display. 9. Daca valoarea intoarsa de aceasta este true metoda va “desena” pe suprafata componentei un mesaj de salut continand numele utilizatorului curent.*.add("Panel 2". comanda managerului de amplasare se face apeland metoda showPanel(int panelNr) a clasei parinte. private Panel2 p2. Cele doua componente vor fi amplasate de managerul implicit BorderLayout in centru si respectiv la sud. String getUser() care intoarce stringul usr si int getCount() care intoarce valoarea lui cnt. Clasa va prevedea metoda public void startSesiune(String usr. subclasa a clasei Canvas si un buton bExit.// ascunde fereastra . cnt si sesiune comandand apoi managerul de amplasare al ferestrei parinte sa faca vizibil panoul 2. int cnt) care va seta variabilele usr .// inchiderea fereastrei si terminarea aplicatiei return true. p1=new Panel1(p2).awt. setLayout(mainLayout).p1).*.//autorizare inchidere fereastra mainLayout=new CardLayout(). add("Panel 1". } public boolean handleEvent(Event e){// procesarea evenimentelor if(e.120).handleEvent(e). import java. } return super.WINDOW_DESTROY){// cerere sistem de inchidere // a fereastrei quit(). // dimensionarea si afisarea ferestrei resize(300.// titlu fereastra canClose=true. Aceste informatii sunt obtinute prin apelul metodele getUser() si getCount() ale clasei parinte. Clasa mai prevede metodele boolean isSesiune() care intoarce valoarea flagului sesiune. class RAFTest extends Frame{ private boolean canClose.// setare manager de amplasare // creare celor doua panouri si adaugarea lor la fereastra p2=new Panel2().id==e. Va fi redefinita metoda action() astfel incat la actionarea butonului bExit va seta pe false valoarea variabilei membru sesiune va atribui valoarea null variabilei usr si valoarea 0 lui cnt comandand apoi managerul de amplasare al ferestrei parinte sa faca vizibil panoul 1.io.

gc. private GridBagConstraints gc=new GridBagConstraints().1).//panoul 1 in varful stivei break.exit(0).0.3.2 tMsg.// creaza fereastra principala } } class Panel1 extends Panel{// Panoul numarul 1 private String name. //Amplasarea campurilor text gc.// caracter de mascare parola setLayout(gl).1.1 // etichete private Label lUsr=new Label("User :"). case 2: mainLayout.Note de curs dispose().// numar de sesiuni de lucru efectuate private Panel2 p2. gc. //Amplasarea etichetelor gc.// manager de amplasare // amplasare componente pe panoul nr. switch(nr){ case 1: mainLayout.gl.// numele utilizatorului private int cnt.// campul de mesaje-> read-only tPsw.PROGRAMARE IN JAVA .gl.NONE.1.gc. bNew= new Button("New"). tPsw= new TextField().// panoul 2 in varful stivei break.weightx=0.setEditable(false). } } public static void main(String[] args){ RAFTest win=new RAFTest().gl.3.setEchoCharacter('*'). addComponent(tUsr.1.// termina aplicatia 259 } } public void closeEnable() {canClose=true.gc.anchor=gc.1 // setari p2=p. lPsw=new Label("Password :").last(this).// referinta panou nr.first(this).// referinta la panoul 2 private NewUserDialog dlg. public Panel1(Panel2 p){// Constructorul panoului nr. // managerul de amplasare private GridBagLayout gl=new GridBagLayout(). gc. addComponent(tPsw.}// autorizare terminare public void closeDisable() {canClose=false.1).fill=gc.// fereastra de dialog // Componentele panoului nr. bQuit = new Button("Quit").HORIZONTAL.}// interzicere terminare public void showPanel(int nr){// aduce in varful stivei panoul nr.gc. . // campuri text private TextField tUsr= new TextField().//elibereaza resursele alocate ferestrei System.weightx=1. addComponent(lPsw. // butoane private Button bOk= new Button("Ok").0.gl.1 gc.fill=gc.gc.1).1). tMsg= new TextField().0.EAST.1.0. addComponent(lUsr.1.1.weighty=0. bRst= new Button("Reset").

1). int width. err=0.gl. }else if(e.2. gc.3.1.// fereastra parinte if(e. Object o){ RAFTest parent=(RAFTest)getParent().2. //Amplasarea butoanelor gc.target==bOk){// actionarea butonului “Ok” if(autentificareUser()){// Daca userul a fost acceptat parent. 2 p2.setText("").BOTH. add(c). dlg=new NewUserDialog(this).gc.4.// user.* * torului dupa numele de user si parola.gridy=row.* * mea hight celule.2. addComponent(bRst. Fiecarui tip de eroare i-a fost asociat * * un numar intreg err.int col.1.2.gridx=col. } // Procesarea evenimentelor generate la actionarea butoanelor public boolean action(Event e. Componenta va fi amplasata in celula * * din randul row si coloana col si va avea latimea width si inalti. cnt).gl.target==bRst){ // actionarea butonului “Reset” tUsr.0.1.gc).gl. } /*******************************************************************\ * Metoda error este apelata de metoda de autentificare a utiliza.weighty=1.1).quit(). Ocuparea spatiului astfel alocat se face conform* * specificatiilor din obiectul GridBagConstraints – parametrul gc. } /*******************************************************************\ * Metoda addComponent este folosita de constructor pentru adaugarea * * unei componente c la panou. addComponent(bOk.// sterge continutul campurilor tPsw.1).gl. parola si mesaje tMsg.//creaza fereastra de dialog }else if(e.gc.// Incepe sesiunea } }else if(e. gl.gridheight=height. gc. Metoda * * error() afiseaza mesajul corespunzator tipului de eroare si retur-* * neaza true daca err=0 sau false daca r!=0. "Trebuie completat campul User!".setText(“”).startSesiune(name. .// dezactiveaza toate componentele disable().gc.// panoului si panoul in sine. addComponent(bQuit. addComponent(bNew. GridBagLayout gl.setConstraints(c. * \*******************************************************************/ private void addComponent(Component c.// Adu in varf panoul nr.// Solicita terminarea aplicatiei } return true.2.target==bNew){ // actionarea butonului “New” disableComponents().1. * \*******************************************************************/ private boolean error(int err){ // tablou de stringuri continand mesajele de eroare String msg[]={"".setText("").0.260 CURS 21 addComponent(tMsg.1). gc.1.fill=gc. In timpul acestei operatii * * pot apare diferite erori.Daca nu a aparut nici o eroare. int height){ gc.gc.gc. gc.gridwidth=width.target==bQuit){ // actionarea butonului “Quit” parent.1).showPanel(2).3.gl. int row. GridBagConstraints gc.

b. * \*******************************************************************/ private boolean autentificareUser(){ int err=0. Daca stringurile sunt identice utilizatorul este accep..length()].length())==0)return error(1).dat.skipBytes(8).getBytes(0.usr.// inchide fisierul if(err!=0) { dat."rw"). if((len=usr.i<8.* * catorul usrID folosit drep cheie de cautare in fisierul cu aces * * aleator usr. Se * * cripteaza parola introdusa de utilizator in usrPsw si se compara * * cu stringul citit din fisierul usr.pos.}// EOF ->nu s-a gasit ndx.getBytes(0. usrPsw. RandomAccessFile ndx.0).id. // deschide fisierele usr.i++){ usrID *=256. } usrPsw=tPsw.dat". for(i=len.dat ndx=new RandomAccessFile("usr.0).0). }// Daca s-a gasit.ndx si usr.ndx".usrPsw.getBytes(0.getText(). usr=tUsr."rw").Note de curs "User neinregistrat!". String psw.len.setText(msg[err]). dat=new RandomAccessFile("usr. * * Daca numele de user este valid se genereaza pe baza lui identifi.ndx.close().b. for(i=0. sau daca pe parcursul* * executiei apar alte erori metoda intoarce false.7. long usrID=0. 261 } /*******************************************************************\ * Metoda autentificareUser() citeste si valideaza numele de user * * introdus de utilizator acesta trebuind sa nu fie un string vid. "Parola incorecta!".readLong())!=usrID){ ndx.length.i<8. // Intoarce true daca err=0 sau false in caz contrar return (err==0? true:false). In caz contrar. Daca inregistrarea cu campul id=usrID este gasita* * valoarea din campul pos a acesteia este folosita pentru a accesa * * inregistrarea cu datele utilizatorului din fisierul usr.getText().i++)b[i]=0. . return error(err). // calculeaza id-ul userului if(len<8){ usr.i. "Eroare la accesarea bazei de date"}.dat din campul parola in varia-* * bila psw.b. } // validare nume user try{ pos=0.b. usrID +=b[i]. // cauta inregistrarea cu campul id=usrID try{ while((id=ndx.readLong(). }catch(EOFException e){err=2.dat.close(). }else usr.len. citeste campul pos pos=ndx. byte b[]=new byte[8].// citeste parola introdusa // Criptare parola b=new byte[usrPsw.err tMsg. // afiseaza mesajul asociat erorii nr.PROGRAMARE IN JAVA .* * tat si metoda intoarce true.

bRst. // creare butoane private Button bOk= new Button("Ok"). } /*******************************************************************\ * metodele enableComponent() si disableComponent() activeaza respec-* * tiv dezactiveaza campurile de editare si butoanele panoului nr.out.toString()). bNew.enable(). bNew. usrPsw=new String(b.dat // inscrie inregistrarea cu contorul actualizat dat.readInt().enable().disable().enable().writeUTF(name). lPsw1=new Label("Password:"). private GridBagConstraints gc=new GridBagConstraints().262 CURS 21 for(i=0.writeInt(cnt). tMsg= new TextField().equals(psw))err=3. bRst.dat dat. } } class NewUserDialog extends Dialog{//fereastra de dialog private Panel1 panel.readUTF().seek(pos). .0). lUsr=new Label("User :"). bRst= new Button("Reset").readUTF().seek(pos).dat if(!usrPsw.disable().writeUTF(usr). titlul si tipul ferestrei de dialog super((Frame)p.println(e. dat.i<b. bQuit.i++)b[i]+=(byte)(i%3+1).readUTF(). dat.enable().// compara parolele }catch(IOException e){// eroare la accesarea fisierelor err=4.// parola cnt =dat. // creare campuri text private TextField tName= new TextField().1 * \*******************************************************************/ public void enableComponents(){ tUsr. System.enable().// contorul de sesiuni cnt++. bCancel = new Button("Cancel"). bOk.// inchide fisierul usr. dat.disable().length. bQuit.enable(). // Citeste inregistrarea din fisierul usr.disable(). } return error(err). tUsr= new TextField(). tUsr. public NewUserDialog(Panel1 p){// Constructorul clasei // seteaza parintele. tPsw2= new TextField().disable(). name=dat. dat.// referinta la panoul nr1 // creare etichete private Label lName=new Label("Name :").// nume de user psw =dat.true). // creare manager de amplasare private GridBagLayout gl=new GridBagLayout(). bOk.getParent().close(). lPsw2=new Label("Reenter :").// actualizeaza contorul dat.writeUTF(psw)."New Usr Account". tUsr.// repozitioneaza pointerul in usr.disable(). tPsw1= new TextField(). } public void disableComponents(){ tUsr.// nume utilizator usr =dat.

Componenta va fi amplasata in celula * * din randul row si coloana col si va avea latimea width si inalti. // caracter mascare parola setLayout(gl).weightx=0.gl.1).gl. gc.1.weightx=1.0.0. }else if(e.gc. gc.gc.gl.4. resize (300.// caracter mascare parola tPsw2.1.1).gc. addComponent(tName. addComponent(lName.2. GridBagConstraints gc.setConstraints(c.2.target==bOk){// actionare buton “Ok” // inregistrare user nou si terminare if(addUser())cancel().0.gl.fill=gc.PROGRAMARE IN JAVA .0.gridx=col.// terminare } . gc.1.6.weighty=1.fill=gc.HORIZONTAL. gl. gc.1). Ocuparea spatiului astfel alocat se face conform* * specificatiilor din obiectul GridBagConstraints – parametrul gc.gridwidth=width.120).0. panel=p. gc.2.1. addComponent(lUsr. } // Procesarea evenimentelor generate la actionarea butoanelor public boolean action(Event e. addComponent(tUsr. GridBagLayout gl.target==bRst){ // actionare buton “Ok” reset(). //Amplasarea etichetelor gc.* * mea hight celule. Object o){ if(e.1).gridy=row.3.gl.anchor=gc.gl.1).Note de curs 263 // interzice terminarea aplicatiei ((RAFTest)getParent()).gridheight=height.1).NONE.2. * \*******************************************************************/ private void addComponent(Component c.3.EAST.// seteaza managerul de amplasare gc.1).1.setEchoCharacter('*'). //Amplasarea butoanelor gc.1).gl. int height){ gc.4.weighty=0. addComponent(tMsg. int row.gc.gc.4.1.0.1.gc.0.1).setEditable(false).closeDisable().target==bCancel){ // actionare buton “Cancel” cancel(). addComponent(lPsw1.gl. addComponent(bOk.2. tMsg. } /*******************************************************************\ * Metoda addComponent este folosita de constructor pentru adaugarea * * unei componente c la panou.1.1).gl.BOTH. addComponent(lPsw2. addComponent(bCancel.2. gc. //Amplasarea campurilor text gc. addComponent(bRst. show().1).gl.fill=gc.2.gc.gc.// camp mesaje -> read-only tPsw1.setEchoCharacter('*').3.gc. addComponent(tPsw1.gc. gc.gc. int width.1). add(c).2.1.0.2.int col.gc.1.gc).2.gl.// stergerea tuturor campurilor text }else if(e.gl.2. addComponent(tPsw2.

getText()))return error(2).i<8.getBytes(0.setText(""). }else usr.getBytes(0. int len.getText().b. tMsg.b.id.getText(). "Trebuie completat campul Nume!".i. Alegeti alt nume de user!". // validarea numelui utilizatorului if(name. } /*******************************************************************\ * Metoda error este apelata de metoda addUser() de inregistrare a * * utilizatorului in baza de date. "User existent. return (err==0? true:false).// reactiveaza componentele panel.setText(msg[err]).ndx si usr. long usrID=0.0). * \*******************************************************************/ private boolean error(int err){ String msg[]={"".usr.len. name=tName.equals(tPsw2. if((len=usr. // calculeaza id-ul userului if(len<8){ usr. tPsw2.0).264 CURS 21 return true. // validare parola1 prin comparare cu parola2 psw=tPsw1. // validare nume user usr=tUsr.getText().dat.enable().length()==0)return error(1). In timpul acestei operatii pot * * apare diferite erori.Daca nu a aparut nici o eroare. hide().setText("").setText(“”). // panoului 1 si panoul insusi // autorizare terminare aplicatie ((RAFTest)getParent()).// ascunde fereastra de dialog dispose().} // verificare daca userul cu identificatorul usrID exista try{// deschide fisierele bazei de date ndx=new RandomAccessFile("usr.i++)b[i]=0.setText("").// elibereaza resursele alocate ferestrei } private void reset(){// sterge continutul campurilor text tName.closeEnable().dat* \*******************************************************************/ private boolean addUser(){ String name.* * zatorului in baza de date formata din fisierele usr. int err=0.i<8. err=0. if(!psw. } /*******************************************************************\ * Metoda addUser() implementeaza procedura de inregistrare a utili."rw").enableComponents(). tUsr. RandomAccessFile ndx. usrID +=b[i].i++){usrID *=256. tPsw1. } private void cancel(){// procedura de terminare dialog panel. Fiecarui tip de eroare i-a fost asociat un * * numar intreg err.psw.ndx". tMsg. byte b[]=new byte[8]. Metoda * * error() afiseaza mesajul corespunzator tipului de eroare si retur-* * neaza true daca err=0 sau false daca r!=0.setText(""). "Trebuie completat campul User!". "Eroare la introducerea parolei!".length())==0)return error(3). for(i=0. . for(i=len.7. "Eroare la accesarea bazei de date"}.

readLong().length()].// inchide fisierul index usr.PROGRAMARE IN JAVA .Note de curs 265 dat=new RandomAccessFile("usr. System.// managerul de amplasare add("Center".// inscrie numele de user dat.dsp).// pozitioneaza pointerul in usr.writeLong(usrID).ndx ndx.//inchide fisierul usr.dat ndx.// tratarea altor evenimente } } // panoul numarul 2 class Panel2 extends Panel{ private boolean sesiune=false.dat }catch(IOException e){// eroare la accesarea fisierelor err=5.close().// inchide fisierul usr.toString()).id==e. psw=new String(b.dat return error(err). } /*******************************************************************\ * Metoda startSesiune() initiaza operatiile de incepere a unei sesi-* .dat".skipBytes(8).length. } public boolean handleEvent(Event e){//procesarea evenimentelor if(e. // crearea componentelor panoului nr.writeInt(0).writeUTF(name).// inscrie parola dat.// terminare citire } ndx."rw").// eroare break.writeUTF(psw).2 private Display dsp=new Display(this). private int cnt.dat dat.ndx dat.i<b.handleEvent(e).dat ndx.i++)b[i]+=(byte)(i%3+1).close().out.// inscrie pointerul in usr. } return super.println(e.// citeste id if(id==usrID){// daca user existent err=4.bExit).length.writeUTF(usr).0).//inscrie contorul de sesiuni = 0 dat.close(). private String name.// componenta display private Button bExit=new Button("Exit").ndx id=ndx.// inscrie numele utilizatorului dat.seek(pos).// intoarce false } // Criptare parola b=new byte[psw.// butonul “Exit” public Panel2(){ setLayout(new BorderLayout()). // adaugare componente add("South".// inchide fisierul usr.length(). for(i=0.getBytes(0.ndx dat.// terminare dialog return true.b.0).writeLong(pos).// urmatoarea inregistrare } }catch(EOFException e){}// sfirsit de fisier if(err!=0) {// eroare la inregistrare user ndx. } return error(err). try{ while(true){// citeste o inregistrare din usr.// inscrie identificatorul long pos=dat. psw.b.WINDOW_DESTROY){// cerere sistem de inchidere cancel().close().//calculeaza pozitia in usr. // inregistreaza user in fisierul usr.

isSesiune()){ Dimension d=size(). } } class Display extends Canvas{ Panel2 p.drawString("ca apelezi a "+p. public Display(Panel2 p2){ p=p2. 0.2 este prezentata interfata grafica afisata de aplicatie in diferite etape ale executiei.cnt=cnt.height/2).266 CURS 21 * uni de lucru a utilizatorului autentificat curent * \*******************************************************************/ public void startSesiune(String name. g. g. this. } } } In figura 21.d. setBackground(Color.drawString("la serviciile mele!". ((RAFTest) getParent()).repaint(). } // Interfata cu display-ul public boolean isSesiune(){return sesiune.} public boolean action(Event e.int cnt){ sesiune=true.this. } public void paint(Graphics g){ if(p.white). } public int getCount(){ return cnt.drawString("Iti multumesc "+p.getUser().2 Interfata grafica a programului RAFTest.21.class .} public String getUser(){ return name.d. Fig. 0. return true. 0.name=name.d.height/2-20).getCount()+"-a oara ".showPanel(1). g.height/2+20). Object o){ sesiune=false.

Animatia consta in reprezentarea succesiva a unor cadre. Alterarea totala sau partiala a imaginii ferestrei pe display era sesizata de sistemul de operare ( care gestioneaza sistemul de ferestre) si acesta ere cel care determina executia metodei paint() ori de cate ori considera ca este necesar.200). class Play extends Frame{ private int rataRefresh=100.white). dupa care sa solicite redesenarea acesteia pentru noile date prin apelul metodei repaint(). add("Center". diferit de cel precedent.1 Succesiunea de cadre a unui desen animat Daca succedarea cadrelor are loc la intervale de timp suficient de mici astfel incat ochiul uman sa nu perceapa pauza dintre cadre. . In exemplele din acele cursuri desenarea era executata de metoda callback paint() ori de cate ori era necesara “reamprospatarea” ferestrei . In acest fel. public Play(){ super("Demo Animatie").22.PROGRAMARE IN JAVA . fiecare cadru continand o alta imagine (vezi figura 22.setBackground(Color. Ca urmare imaginea desenata era statica (cel mult redimensionata in cazul modificarii dimensiunii “canvasului” de catre managerul de amplasare) modificanduse doar ocazional la redimensionarea ferestrei. resize(200. al textului si a unor imagini incarcate din fisiere in format GIF sau JPG. In acest fel un thread al aplicatiei poate modifica periodic un set de date folosite de metoda paint() la desenarea imaginii. private Film film=new Film(). Sa analizam urmatorul exemplu care deplaseaza o discheta in fereastra aplicatiei: import java. Animatia presupune redesenarea periodica a imaginii.1).Note de curs 267 Curs 22 Animatie In cadrul cursurilor 12 si 13 am discutat aspecte legate de desenarea pe suprafata unui control derivat din clasa Canvas a primitivelor grafice. este creata senzatia de miscare – animatia imaginii.*. film. Fig. imaginile afisate se vor modifica periodic realizand astfel animatia.awt. Am vazut ca metoda paint() poate fi initiata nu numai de sistemul de operare ci si de aplicatie prin apelul metodei repaint().film). la fiecare redesenare fiind “pus pe tapet” un cadru nou.

. } public boolean handleEvent(Event e){ if(e.handleEvent(e). } public static void main(String[] args){ Play win=new Play(). g.2+locy. g.rataRefresh).y[2]=80+locy.black). firstTime=false. private boolean firstTime=true. g.y[5]=0+locy.cadruNou(). static final byte WIDTH=80. g.x[1]=80+locx.y[1]=0+locy. if(args.y.6.setColor(Color.drawPolygon(x.50+locy. g.10. static final byte STEP=2.10). int y[]=new int[6]. dispose().darkGray). return true.false).drawRect(25+locx.30).x[5]=0+locx.black).length!=0) win. static final byte DOWN=1.setColor(Color. g.black).setColor(Color.width-WIDTH)/2. static final byte HEIGHT=80.WINDOW_DESTROY){ hide().45.x[4]=0+locx.fillRect(25+locx.drawRoundRect(10+locx.setColor(Color.60.y[4]=70+locy.60. x[0]=0+locx. . for(. } catch(InterruptedException e){} win. } String s="MICRO ". static final byte RIGHT=3. private int locx. int x[]=new int[6].fillPolygon(x. y[0]=0+locy.45.6).white).film.x[2]=80+locx.30). public void paint(Graphics g){ if(firstTime){ locx=(size().id==e. y[3]=80+locy.10.setColor(Color. } } } class Film extends Canvas{ static final byte UP=0.parseInt(args[0]).exit(0).6). g.locy. g. private byte state=UP.50+locy. g.0+locy.setColor(Color.6.){ try{ Thread. static final byte LEFT=2.draw3DRect(72+locx. g.fillRoundRect(10+locx. locy=(size(). g.0+locy. g.10). x[3]=10+locx.268 CURS 22 show().rataRefresh=Integer.sleep(win.gray).y. } return super.45.height-HEIGHT)/2.45. g. System.

setColor(Color. break.30).setColor(Color.width-WIDTH))state=LEFT.52+locy.40. g. aceasta fiind amplasata in centrul ferestrei si redimensionata de managerul de .class Metoda paint() a clasei Film deseneaza discheta din figura pe o componenta Canvas. g.fillRect(30+locx.50+locy.2 – Imagini la diferite momente de timp ale ferestrei aplicatiei Play.height-HEIGHT))state=UP. g.black).25+locx.30).25). g.15+locy). if(locx < 0)state=DOWN. } } 269 In figura 22. if(locx > (d. switch(state){ case DOWN: locy+=STEP.52+locy. case RIGHT: locx+=STEP. } repaint(). } public void cadruNou(){ Dimension d=size(). break.2 sunt redate cateva imagini ale ferestrei aplicatiei la momente diferite de timp.7.drawRect(30+locx.25).Note de curs g. case UP: locy-=STEP. if(locy > (d. Fig.40.7.fillRect(20+locx.lightGray).50+locy.PROGRAMARE IN JAVA . break. g. if(locy < 0)state=RIGHT.setColor(Color.drawString(s.22.drawRect(20+locx.black). g.setColor(Color. g.darkGray). case LEFT: locx-=STEP. g. break.

System. resize(200.) care la fiecare iteratie apeleaza metoda cadruNou() a clasei Film. Aceasta rata de “reinprospatare” a desenului are valoarea implicita 100 ms dar poate fi schimbata specificand in linia de comanda un alt timp de refresh ( o valoare intreaga reprezentand temporizarea in ms). dispose(). La prima desenare. private Film film=new Film().film). import java. discheta “miscandu-se” de 5 ori mai incet decat inainte. aceste coordonate pastrate in variabilele locx si locy sunt stabilite astfel incat discheta sa fie desenata in centrul canvas-ului iar directia de deplasare a acesteia este stabilita in sus (UP).200). LEFT – constante definite in clasa Film) data de variabila statei incrementeaza/decrementeaza fie pe locx fie pe locy cu pasul constant STEP = 2. Daca locx sau locy ating valori care ar face ca la desenarea dischetei aceasta sa iasa din limitele canvas-ului ( ale carei dimensiuni se afla apeland metoda size()). rata de refresh va fi setata la 0. DOWN. In cadrul metodei main() a aplicatiei este prevazut un ciclu infinit for(.*.. add("Center". directia de deplasare este schimbata.1) pot fi afisate succesiv.WINDOW_DESTROY){ hide().exit(0).270 CURS 22 amplasare BorderLayout astfel incat sa ocupe intreaga ferestra. } return super.id==e. public Play(){ super("Demo Bucla de Imagini"). Discheta este desenata cu coltul din stanga sus in punctul de coordonate (locx.b). add("South". imaginea dischetei aparand translatata pe orizontala sau pe verticala (in functie de directia de deplasare) cu STEP pixeli. se introduce dupa apelul metodei repaint() o temporizare prin dezactivarea threadului principal pe o perioada de timp specificata de variabila rataRefresh. class Play extends Frame{ private int rataRefresh=100. Dupa ce si ulima imagine a fost desenata. Dupa stabilirea noilor coordonate sau a directiei.awt. se reia succesiunea cu desenarea primei imagini. in bucla realizandu-se astfel animatia acestora. Dezactivarea threadului principal se face apeland metoda Thred.handleEvent(e). setResizable(false). show().5 secunde. } public boolean handleEvent(Event e){ if(e. Programul urmator exemplifica implementarea unei astfel de bucle de imagini. } . Bucle de imagini Am vazut ca pe o componenta derivata din clasa Canvas se poate desena si o imagine continuta intr-un fisier. Mai multe astfel de imagini (cum ar fi cele din figura 22. Aceasta metoda in functie de directia de deplasare curenta (UP. Pentru ca animatia sa nu fie prea rapida. este apelata metoda repaint() care la randul sau va determina executia metodei paint(). return true. private Button b=new Button("Start"). RIGHT.sleep().locy) ale ferestrei. De exemplu daca programul se lanseaza in executie cu comanda C:\>java Play 500. Aceasta va reface desenul dischetei de data aceasta cu coltul din stanga sus intr-un punct diferit de desenarea precedenta.

programul afiseaza imagini preluate din fisiere in format GIF.){ try{ win.gif in tabloul Image img[] de 15 elemente . film.} public void start(){ state=true.PROGRAMARE IN JAVA .width-WIDTH)/2.Note de curs public boolean action(Event e. else if(cadru >=20 && cadru <26)i=14. Object o){ if(film. private boolean state=false.isRunning()){ b.gif".height-HEIGHT)/2. } } 271 } Programul este foarte asemanator cu cel anterior.stop(). } } public boolean isRunning(){ return state. } return true.} public void stop(){ state=false.getDefaultToolkit(). private int cadru=0.. Dimension d=size().gif .setLabel("Start"). img[i]=Toolkit.i++){ String imageFile="exp"+(i+1)+". . g.getImage(imageFile). film.start(). cadru++.this).parseInt(args[0]).} public void paint(Graphics g){ int i=0.(d. if(args. if(state){ if(cadru >=0 && cadru <3)i=0. for(.film. private static final int HEIGHT=98.exp15. public Film(){ setBackground(Color. Thread. } catch(InterruptedException e){} } } } class Film extends Canvas{ private static final int WIDTH=98. cadru%=26.repaint().setLabel("Stop").sleep(win.black). else if(cadru >=12 && cadru <16)i=9.rataRefresh=Integer. for(int i=0.i<15. cu exceptia faptului ca de aceasta data in loc sa traseze primitive grafice..rataRefresh).drawImage(img[i]. }else{ b.length!=0) win. private Image img[]=new Image[15]. } public static void main(String[] args){ Play win=new Play(). else if(cadru >=16 && cadru <20)i=cadru-6. else if(cadru >=4 && cadru <12)i=cadru-3.Aplicatia incarca imaginile din fisierele exp1.. (d.

13] . Dupa incarcarea imaginii din fisier threadul respectiv este distrus.2 – Imagini la diferite momente de timp ale ferestrei aplicatiei Play. class Play extends Frame{ private Film film=new Film().cadrele 0-3 – imaginea img[0] . Aici el afiseaza imaginile referite de elementele tabloului img. . aplicatia deseneaza numai o parte din imaginile buclei. sarind peste unele imagini si afisand in locul lor “pete” albe. Fig.. Aceasta ne indreptateste sa modificam programul anterior astfel: import java.drawImage() nu va “desena” nimic pe suprafata “canvas”-ului aceasta ramanand alba pana nu se va desena o imagine incarcata deja.*.22.cadrele 12-15 – imaginea img[10] .cadrele 4-11 – imaginile img[2.. Acest fenomen se explica prin faptul ca pentru incarcarea fiecarei imagini din fisier. Astfel incat unele din aceste threaduri nu apuca sa incarce imaginea in timp ce threadul principal deja apeleaza metoda repaint() care determina threadul AWT care gestioneaza interfata grafica sa execute metoda update() care dupa ce sterge suprafata de desenare cu culoarea de fundal apeleaza metoda paint() pentru desenarea propriuzisa.cadrele 16-19 – imaginile img[11.cadrele 20-25 – imaginea img[14] In figura 22.class La executia acestui program se constata un fenomen aparent ciudat – in primele cicluri de executie. metoda loadImage() lanseaza cate un thread separat. apeleaza metoda paint().awt. “Petele” albe care apar intre imagini se datoreaza deci “stergerii” de catre metoda update() a suprafetei de desenare cu culoarea selectata pentru fundal (background).272 CURS 22 Programul afiseaza 26 de cadre astfel: . In consecinta metoda g.9] .2 sunt redate cateva imagini ale ferestrei aplicatiei la momente diferite de timp. Unele dintre aceste elemente refera imagini deja incarcate dar altele inca au valoarea null si nu refera nici o imagine deoarece threadul care o incarca din fisier nu a terminat sau nici nu a inceput inca aceasta operatie. Dupa ce a efectuat aceasta operatie. metoda update().

isRunning()){ b. } return super. private Image img[]=new Image[26]. else if(cadru >=12 && cadru <16)i=9. cadru%=26. System. resize(160. }else{ b. setResizable(false). add("South".gif". } } class 273 Film extends Canvas{ private static final int WIDTH=98. } return true. } public static void main(String[] args){ Play win=new Play().} public void start(){ state=true. } } public boolean isRunning(){ return state. cadru++. return true.handleEvent(e).id==e. for(int i=0. private int cadru=0.WINDOW_DESTROY){ hide().film).Note de curs private Button b=new Button("Start"). public Film(){ setBackground(Color.drawImage(img[i].b).getDefaultToolkit().setLabel("Start"). if(state){ if(cadru >=0 && cadru <3)i=0. private static final int HEIGHT=98.160). Object o){ if(film.i<15.exit(0).(d. else if(cadru >=4 && cadru <12)i=cadru-3.black).setLabel("Stop"). dispose(). g.} public void paint(Graphics g){ int i=0.i++){ String imageFile="exp"+(i+1)+".getImage(imageFile). film.} public void stop(){ state=false. show().this).height-HEIGHT)/2. else if(cadru >=20 && cadru <26)i=14. add("Center". else if(cadru >=16 && cadru <20)i=cadru-6. } public boolean handleEvent(Event e){ if(e. public Play(){ super("Image Loop"). private boolean state=false. film.PROGRAMARE IN JAVA . . (d. img[i]=Toolkit. } public boolean action(Event e.stop().width-WIDTH)/2.start(). Dimension d=size().

generat si transmis si deci si sosit mai tarziu. Aceasta metoda nu apeleaza direct metoda update() ci produce si transmite sistemului de operare un mesaj-cerere de reimprospatare a ferestrei aplicatiei revenind apoi in repaint() de unde va reveni inapoi in paint() si de aici in update(). La revenirea din update(). Threadul AWT va apela metoda handleEvent() transmitandu-i acest mesaj ca eveniment WINDOW_DESTROY. sistemul de operare va plasa imediat mesajul de notificare corespunzator in coada de mesaje. etc. threadul preia un mesaj din coada de mesaje. } catch(InterruptedException e){} repaint(). si intarzierea ar fi fost mai mare programul devenind incomod de folosit. Problema este ca raspunsul la comanda a venit cu o intarziere de peste 300 ms. Dupa expedierea mesajului-cerere de redesenare. Aparent se formeaza un lant de apeluri infinit care in final va umple stiva si va bloca executia aplicatiei. actionare controale. Intrucit mesajul de terminare a fost plasat de sistem in coada de mesaje inaintea mesajului cerere de redesenare. Pana la urma. se dezactiveaza pentru 300 de ms. La terminarea executiei metodei update(). poate fi folosita urmatoarea tehnica. miscare mouse. Clasa MediaTracker Pentru a elimina fenomenul neplacut de la inceputul executiei buclei de imagini. Aceasta are insa si o consecinta neplacuta. Intre timp threadul WT este ocupat in continuare cu desenarea unei imagini. Daca contine mesaje. Dupa desenare. threadul va astepta sosirea unui mesaj.274 CURS 22 } try{ Thread. fara a incarca insa stiva threadului cu adrese de revenire. threadul AWT va intra intr-o bucla de preluare a mesajelor primite de la sistemul de operare. lantul de apeluri oprindu-se aici. apasare taste. el va extrage din coada de mesaje si mesajul-cerere de redesenare generatsi expediat tot de el. Metoda handleEvent() va trata acest eveniment inchizand fereastra. metoda paint() apeleaza la sfarsitul sau metoda repaint(). cand desenarea cadrelor incepe inainte de a se incarca toate imaginile. el va fi extras inaintea celuilalt. alterarea unei parti din fereastra prin acoperirea de o alta ereastra. In realitate threadul AWT care executa metoda paint() va apela numai metoda repaint(). dupa care se “trezeste” si incepe executia metodei repaint() din care va expedia un mesaj-cerere de initiere a executiei metodei update(). Aplicatia este blocata pana cand nu au fost incarcate toate . Daca coada de mesaje este goala. Sistemul de operare care gestioneaza mesajele. } } In aceasta versiune. eliberand resursele alocate si terminand in final executia aplicatiei. va plasa mesajul in coada de mesaje a aplicatiei. In consecinta. va stabili despre ce eveniment este vorba si va incepe tratarea acestuia. Aceasta va apela metoda update() care va sterge “canvas”-ul si va apela metoda paint() care la randul sau va apela metoda repaint() etc. Procesul se reia astfel la infinit. minimizare/maximizare. va incepe executia metodei update(). Daca rata de refresh ar fi fost mai mare. Daca in momentul in care threadul AWT incepe desenarea. Mesajele din coada sunt de fapt notificari ale sistemului de operare asupra evenimentelor privitoare la fereastra aplicatiei – redimensionare. va extrage si va prelucra primul mesaj. revine in repaint() din care revine in paint() si inapoi in update().sleep(300). cerere de inchidere. utilizatorul actioneaza butonul sistem de terminare a executiei.

putand fi o valoare intreaga distincta). se inregistreaza imaginile in curs de incarcare cu metoda addImage() definita in clasa MediaTracker: imageTracker.PROGRAMARE IN JAVA . checkID(). se foloseste metoda clasei MediaTracker . unde i este identificatorul folosit de pentru inregistrarea obiectului(nu este obligatoriu sa fie neaparat i.i<15. Acesta apel blocheaza programul a carui executie va fi reluata numai dupa ce incarcarea imaginii cu identificatorul 0 din fisierului va fi terminata. in acest rastimp ea putand sa faca alte prelucrari. } catch(InterruptedException e){} } . boolean b) – intoarce true daca incarcarea imaginii inregistrate sub identificatorul id s-a terminat si false daca nu a inceput inca sau inca nu s-a terminat. } try{ imageTracker.. Din acest motiv..getImage(imageFile). Monitorizarea incarcarii imaginilor din fisiere se face folosind un obiect din clasa MediaTracker. De exemplu in constructorul clasei Film se poate declara variabila: MediaTracker imageTracker=new MediaTracker(this).. imageTracker..Note de curs 275 imaginile din fisiere.i). Solutia consta in realizarea desenului intr-un buffer – obiect al clasei Image.waitForID(0). Dubla bufferizare la desenare Desenarea unei imagini pe suprafata componentei nu se face instantaneu.addImage(img[i].getDefaultToolkit(). Acest identificator va fi folosit pentru a determina aplicatia sa astepte pana cand imaginea inregistrata cu acest numar va fi citita integral din fisier. Pentru a nu bloca aplicatia pe perioada incarcarii unei imagini.waitForAll(). Al doilea parametru b daca are valoarea true forteaza inceperea imediata a incarcarii imaginii din fisier daca aceasta operatie inca nu a inceput. MediaTracker imageTracker=new MediaTracker(this). public Film(){ setBackground(Color. Vom folosi in continuare metoda waitAll() pentru a elimina afisarea a numai unora dintre imagini in primele cicluri ale buclei din programul anterior.addImage(img[i]. Crearea bufferului se face apeland . Clasa MediaTracker mai prevede metoda waitForAll() care blocheaza aplicatia pana ce toate imaginile vor fi incarcate. De exemplu pentru a se astepta incrcarea completa a imaginii inregistrate sub identificatorul 0. se va apela metoda waitForID(): imageTracker. Ambele metode “arunca” o exceptie InterruptedException care trebuie prinsa sau aruncata mai departe de catre metoda in cadrul careia se face apelul.i). apare o “palpaire” deranjanta a imaginii animate.gif". img[i]=Toolkit.i++){ String imageFile="exp"+(i+1)+". Dupa ce s-au facut toate apelurile getImage(). Modificarile afecteaza doar constructorul clasei Film astfel: . for(int i=0.black). Un astfel de obiect se creaza cu constructorul: MediaTracker(ImageObserver component) Argumentul constructorului este un obiect tinta al afisarii imaginii apartinand de exemplu unei subclase a clasei Canvas. Aceasta metoda are doi parametri: boolean checkID(int id.

g. g.fillRoundRect(10.25).HEIGHT). g.45.setColor(Color. g. g.// creaza imaginea locx=(size().0}.fillRect(0. In acest fel. } //se modifica metoda paint. locy=(size().// se adauga declaratia bufferului // se adauga metoda de desenare in buffer a dischetei public void createDiskImage(){ String s="MICRO ". .drawString(s. g. g.drawRect(25.80.width-WIDTH)/2.45. createImage(int latimeImagine.y. g.50.setColor(Color.darkGray). g.fillRect(20.fillPolygon(x. imaginea din buffer este pusa “dintr-un foc” (asa cum sunt desenate imaginile preluate din fisiere) pe suprafata componentei.6. g.2.0.setColor(Color.black).darkGray). g.black).setColor(Color. firstTime=false.setColor(Color.fillRect(30. g.52.60. int y[]={0.0.7.drawRect(20. este o versiune a primului program din acest curs (fig. g.0}.6).setColor(Color.getGraphics(). Aplicatia urmatoare. public void paint(Graphics g){ if(firstTime){// initializari createDiskImage().0.height-HEIGHT)/2. Aceasta aloca memoria necesara si intoarce referinta la un obiect Image.HEIGHT).52. private Image diskImage. Desenarea in buffer se face folosind contextul grafic al acestuia obtinut prin apelul metodei clasei Image.10.locy modificate la fiecare cadru nou. imaginile ce urmeaza a fi afisate de metoda paint() pot fi pregatite din timp.white). Modificarile vizeaza numai clasa Film astfel: class Film extends Canvas{ . g.70.setColor(Color.setColor(Color.setColor(Color.white). int inaltimeImagine).10). g.25.WIDTH.45. // desenarea fundalului imaginii g.10).fillRect(25. g.black). g. int x[]={0.setColor(Color..80.draw3DRect(72.7.// crearea bufferului Graphics g=diskImage. eliminandu-se astfel palpairea.25).6.50. Acest context grafic poate fi folosit pentru realizarea desenului in buffer.30). g.22.lightGray).40.10. g.30). acesteia revenindu-i acum rolul doar //de a comanda crearea si desenarea imaginii in buffer ( numai la //prima executie) si apoi afisarea acesteia in coordonatele //locx.black). diskImage=createImage(WIDTH.6). g.45.black).10..276 CURS 22 metoda clasei Component.15).80. In plus acest mecanism permite realizarea desenului de catre o alta metoda decat metoda paint() deoarece nu mai suntem legati de contextul grafic de desenare Graphics g transmis acesteia ca parametru. apeland primitivele grafice cunoscute.50.30). Odata terminata desenarea. g.setColor(Color.60.false).y.0.80. getGraphics().0.drawPolygon(x.2) si exemplifica utilizarea acestei tehnici. g.30).drawRoundRect(10.// obtinerea contextului g.gray).40.50.drawRect(30.

.10).locy.80+locy. Ea poate fi evitata supradefinind metoda clasei Canvas update() astfel incat aceasta sa apeleze metoda paint() direct. String s="MICRO ".10. .setColor(<culoare fundal>).80+locx.black).drawPolygon(x. g. int y[]={locy. private boolean firstTime=true.60.fillRect(25+locx..draw3DRect(72+locx.black).<latimea imaginii>.setColor(Color.10).6). Pentru a elimina si aceasta cauza a “palpairii” datorate sistemului.10. private Image diskImage. Desi stergerea se face foarte rapid.drawRoundRect(10+locx. private int locx. g.45. g.0. g.y.setColor(Color.70+locy. .gray). Intarzierile nu sunt permanente.locx.black).setColor(Color.// deseneaza imaginea } . int x[]={locx.50+locy.6. g. g.Note de curs } g. g.45...d.this). este sezizata de ochiul uman ca “palpaire”.white). g.setColor(Color..setColor(Color.60.darkGray).locy}. } 277 Supradefinirea metodei update() O alta cauza a “palpairii” imaginii este “stergerea” suprafetei de desenare cu culoarea de fundal de catre metoda update().6). g. update() si paint(): class Film extends Canvas{ . iar desenarea imaginii este si ea foarte rapida. in programul precedent vom aduce urmatoarele modificari metodelor createDiskImage().height). g. desenarea imaginii . inainte ca aceasta sa invoce metoda paint().drawImage(diskImage.locx}.locy.45.0.6.drawRect(0. Aceasta pauza intre doua desenari succesive.d..45.<inaltimea imaginii>). g.// contextul grafic al bufferului .locy.80+locx.2+locy. daca este prea lunga. din momentul din care s-a produs stergerea pana in momentul in care threadul AWT va executa metoda paint() poate sa treaca un timp indelungat (zecimi de secunda).PROGRAMARE IN JAVA .locy. private Graphics g.fillPolygon(x. Stergerea imaginii precedente se va face in buffer cu metoda: g. g.30).y.fillRect(0. g.setColor(Color.locx.setColor(Color..80+locy.width.} In acest fel suprafata de afisare nu mai este stearsa si deci nu va mai aparea palpairea. g. public void createDiskImage(){ Dimension d=size().locy.false).drawRect(25+locx.white).10+locx...fillRoundRect(10+locx. fara a mai efectua stergerea suprafetei de desenare: public void update(Graphics g){paint(g). g. g. In acest timp threadul AWT este suspendat si deci suprafata de desenare ramane in perioada respectiva de timp stearsa. fiind cauzate de evenimente in care sistemul de operare este solicitat cu executia unor threaduri de prioritate mai mare.30).50+locy.

setColor(Color. g.lightGray).25).this). g. diskImage=createImage(d.7.fillRect(30+locx.drawImage(diskImage. g.width.50+locy.15+locy).7.d. g.52+locy. } public void update(Graphics g){paint(g).} .fillRect(20+locx. firstTime=false.setColor(Color.drawRect(30+locx.30).darkGray).getGraphics().drawRect(20+locx. locx=(d.black). g.height-HEIGHT)/2.. g.setColor(Color.25+locx.height). } .setColor(Color.0.0.52+locy..25).30).40.40.black). g=diskImage.50+locy.278 CURS 22 g. gContext. } public void paint(Graphics gContext){ if(firstTime){ Dimension d=size().width-WIDTH)/2. } createDiskImage(). g. g.drawString(s. locy=(d.

23.width.y).y0).width.PROGRAMARE IN JAVA . Originea sistemului cartezian de coordonate xOy are coordonatele (0. Imaginea reala din acest cadru va fi scalata de obiectiv si reprodusa la scara pe suprafata filmului prin impresionarea unor granule fotosensibile cu care este acoperita aceasta suprafata. Astfel factorii de scalare pe abscisa si pe ordonata vor fi: . In cazul suprafetei componentei pixelii sunt echivalentii granulelor fotosensibile care acopera suprafata filmului.0). Spatiul real bidimensional se intinde de la plus la minus infinit. Pentru a trasa un grafic in acest spatiu vom alege un punct O ca origine a sistemului de coordonate astfel incat orice punct de pe suprafata plana va putea fi reprezentat in sistemul de coordonate ales printr-o pereche de numere reale (x.height ca in figura 23.width si inaltime w. img. Din intreg planul infinit pe care s-a realizat graficul.1 – Sisteme de coordonate Aceasta fereastra–cadru va avea propriul sau sistem de coordonate x’Oy’ avand originea amplasata in punctul de coordonate (x0.height). Prima problema consta in dimensiunile diferite ale ferestrei – cadru care are dimensiunile (w. w. Fig.height) si a imaginii cu dimensiunile (img. Aceasta impune introducerea unor coeficienti de scalare a coordonatelor tuturor punctelor reproduse.Note de curs 279 Curs 23 Trasarea graficelor in planul real Reproducerea pe suprafata unei componente a unei portiuni din spatiul bidimensional real este foarte asemanatoare cu realizarea unei fotografii. Aici apar insa probleme. Un punct de coordonate (x. Din intreg spatiul.y) in sistemul xOy va avea in sistemul x’Oy’ coordonatele (x-x0. nu putem reproduce decat o portiune finita pe care o incadram intr-o fereastra dreptunghiulara de latime w. aparatul va surprinde doar cadrul vizat de obiectiv.y-y0). Cu cat granulatia materialului fotosensibil care acopera suprafata filmului este mai fina cu atat rezolutia imaginii obtinute este mai buna.1. Toate punctele graficului trasat in planul xOy incadrate de fereastra-cadru ar trebui reproduse pe suprafata imaginii.

h. w=iW. kx=iW/wW.} public void clearRect(double x.double wH.double y0. Pentru ca acest lucru sa nu se intample. import java.y”): x′′ = (int)(( x − x0 ) ⋅ k x ) y ′′ = img.y) unui punct din planul xOy in coordonate imagine (x”. Cunoscind si coordonatele (x0. private int w.getGraphics(). deci coordonatele x” si y” calculate cu formulele de mai sus vor fi convertite in valori intregi. int iW.height kx = A doua problema este sistemul de coordonate x”Oy” al imaginii a carei ordonata este in oglinda fata de sistemul de coordonate x’Oy’ al ferestrei-cadru.*. private Graphics g.createImage(iW. } public void clear(){ g. Formulele de calcul ale coordonatelor punctelor proiectate pe suprafata imaginii vor fi astfel: x′′ = x′ ⋅ k x y ′′ = img. g=img.w.yo.awt.height − (int)(( y − y0 ) ⋅ k y ) Sa construim acum o clasa RealGraphics care joaca rolul aparatului fotografic realizand aceasta transformare.h). De asemenea el va implementa functiile de desenare in planul real al primitivelor grafice.y0) in planul xOy ale coltului din stanga jos al ferestrei-cadru vom deduce formulele de transformare ale coordonatelor (x.h=iH.gc(). aceasta ar face ca reprezentarea graficului din fereastra cadru pe suprafata imaginii sa apara si el in oglinda (rasturnat). double wW.ky=iH/wH.} public void dispose(){ img=null.ky.height − y ′ ⋅ k y A treia problema este ca valorile coordonatelor in fereastra cadru sunt numere reale iar ale coordonatelor imagine sunt numere intregi. } public Image getImage(){return img.clearRect(0.int iH) { xo=x0.280 CURS 23 img.width img. double y. In concluzie. ordonatelor y’ punctelor proiectate li se va aplica dupa scalare si o translformare corectiva.kx. private Image img. public RealGraphics(double x0. class RealGraphics{ private double xo.0.height ky = img.iH). .width img. Component picture. odata stabilite dimensiunile ferestrei-cadru si ale imaginii se pot calcula factorii de scalare pe abscisa si pe ordonata.yo=y0. img=picture. System.

copyArea(ix. g.iy. ih=(int)(height*ky). iy=h-(int)((y-yo)*ky). } public void drawRect(double x. g.drawOval(ix. ih=(int)(height*ky).iw. ih=(int)(height*ky).iy. g.ih.drawLine(ix1. iw=(int)(width*kx).arcAngle). iy=h-(int)((y-yo)*ky).drawArc(ix. } public void draw3DRect(double x.startAngle. double height) { int ix=(int)((x-xo)*kx).raised).idy). boolean raised) { int ix=(int)((x-xo)*kx). double width. double y. double width. double height.clearRect(ix. iy=h-(int)((y-yo)*ky).ix2.ih. ix2=(int)((x2-xo)*kx). double y. double y.int arcAngle) { int ix=(int)((x-xo)*kx).PROGRAMARE IN JAVA . int startAngle. } public void drawOval(double x. double height. g. double height) { int ix=(int)((x-xo)*kx). double width.iy2). ih=(int)(height*ky). double width. } public void copyArea(double x. double y.draw3DRect(ix. g. double y2) { int ix1=(int)((x1-xo)*kx).iy1. idx=(int)(dx*kx).iw. double height. } public void drawLine(double x1. idy=(int)(dy*ky). iy=h-(int)((y-yo)*ky).iw. double dx. double y.iy.ih).idx.iy.ih. double width. } public void drawArc(double x. iw=(int)(width*kx).iw.ih). g. iw=(int)(width*kx).iy.iw. iw=(int)(width*kx). ih=(int)(height*ky).double dy) 281 { int ix=(int)((x-xo)*kx). double height) .Note de curs double width. iy1=h-(int)((y1-yo)*ky). double y1. iy=h-(int)((y-yo)*ky). iy2=h-(int)((y2-yo)*ky). iw=(int)(width*kx). double x2.

for(int i=0. xP=null.i++){ xP[i]=(int)((xPoints[i]-xo)*kx). double height.yP=null. double arcWidth.gc(). yP[i]=h-(int)((yPoints[i]-yo)*ky).i<nPoints. ih=(int)(height*ky). double height.double y) { int ix=(int)((x-xo)*kx). double width. double width. } public void drawRoundRect(double x. iy=h-(int)((y-yo)*ky). iy=h-(int)((y-yo)*ky).raised).double arcHeight) { int ix=(int)((x-xo)*kx). double y. ih=(int)(height*ky). } g. iy=h-(int)((y-yo)*ky).nPoints).iy. double height) { .drawRoundRect(ix.iah). iw=(int)(width*kx). } public void fillOval(double x. yP[]=new int[nPoints].ih).iy.startAngle. g. g.drawString(s.fill3DRect(ix. ih=(int)(height*ky).iw. double width. } public void fillArc(double x. iw=(int)(width*kx). } public void drawString(String s. iw=(int)(width*kx).iw.iw. double y.int nPoints) { int xP[]=new int[nPoints]. g.ix.fillArc(ix. g.double yPoints[].double x.arcAngle). iah=(int)(arcHeight*ky).iy.iaw.yP. boolean raised) { int ix=(int)((x-xo)*kx). iy=h-(int)((y-yo)*ky).iy).282 { CURS 23 int ix=(int)((x-xo)*kx).int arcAngle) { int ix=(int)((x-xo)*kx). System. iy=h-(int)((y-yo)*ky).ih. ih=(int)(height*ky).drawRect(ix. g. } public void fill3DRect(double x.iw.ih. int startAngle. } public void drawPolygon(double xPoints[]. iaw=(int)(arcWidth*kx).iy. iw=(int)(width*kx). double y.ih. double y. double height. double width.drawPolygon(xP.

fillOval(ix. ih=(int)(height*ky). iaw=(int)(arcWidth*kx). } public void { int ix=(int)((x-xo)*kx). g.setColor(c).} public Color getColor(){return g.fillRoundRect(ix. iy=h-(int)((y-yo)*ky). } public void fillPolygon(double xPoints[].gc().} public void setFont(Font f){g. iah=(int)(arcHeight*ky).fillPolygon(xP. double arcWidth. } public void fillRoundRect(double x. iw=(int)(width*kx).toString().getColor(). ih=(int)(height*ky).yP=null. yP[i]=h-(int)((yPoints[i]-yo)*ky).iw.setFont(f). yP[]=new int[nPoints]. double height.PROGRAMARE IN JAVA . double y.iaw.i++){ xP[i]=(int)((xPoints[i]-xo)*kx). iw=(int)(width*kx).Note de curs int ix=(int)((x-xo)*kx). } public String toString(){return g.2 . double y. iy=h-(int)((y-yo)*ky).} public Font getFont(){return g.} public void setXORMode(Color otherColor){g.getFont().getClipRect().} } Programul urmator exemplifica utilizarea acestei clase pentru generarea desenului din figura 23. iy=h-(int)((y-yo)*ky).iah). xP=null. g. double height) 283 { int ix=(int)((x-xo)*kx).i<nPoints. for(int i=0. System.double arcHeight) fillRect(double x.ih.iy).iy. double width.yP.nPoints). g.getFontMetrics().iw.iy.setXORMode(otherColor).setPaintMode(). iy=h-(int)((y-yo)*ky).ih).} public FontMetrics getFontMetrics(){return g.translate(ix.iy.iw. } public Rectangle getClipRect(){return g.} public void setColor(Color c){g.int nPoints) { int xP[]=new int[nPoints].} public void setPaintMode(){g.ih).} public void translate(double x. double width.fillRect(ix. } g. iw=(int)(width*kx). g. double y) { int ix=(int)((x-xo)*kx). ih=(int)(height*ky).double yPoints[].

} } class StarPicture extends Canvas{ private RealGraphics rg.a1.360. resize(400.400).-120. return true.height. drawStar(rg).drawImage(rg. private boolean firstTime=true.d. } g. public Star(){ super("Real Graphics").a3.a2.0.width.awt. show().exit(0).WINDOW_DESTROY){ hide().i<5.r2=45. for(int i=0. } public boolean handleEvent(Event e){ if(e.0. rg.23.d. } public static void main(String[] args){ Star win=new Star(). } return super.id==e.240. starPicture. } public void paint(Graphics g){ Dimension d=size().this.setBackground(Color.2 Desenarea in coordonate reale import java. } private void drawStar(RealGraphics rg) { double r1=120. dispose().getImage().handleEvent(e). firstTime=false.setColor(Color. add("Center".*. System.i++){ .this).starPicture).240. if(firstTime){ initStarPicture().360). public void initStarPicture(){ rg=new RealGraphics(-120. rg.clear().284 CURS 23 Fig. class Star extends Frame{ private StarPicture starPicture.r3.black).white). starPicture=new StarPicture().

0.PI*a2/180). r2*Math.0.cos(Math. for(int i=0.0.0. drawStarPoint(rg.cos(Math.PROGRAMARE IN JAVA .PI*a2/180).sin(Math.PI*a1/180).r1*Math.PI*a2/180).0. } } private void drawStarPoint(RealGraphics rg.y2+(y3-y2)*k).y1+(y2-y1)*k.PI/5). Metoda paint() apeleaza metoda drawStar() transmitandu-i acesteia instrumentul de desenare.PI*a2/180). a2=a1+108. r2*Math.i++){ a1=i*72. r1*Math. a3=a1-36. transmitandu-i la randul sau. a3=a1-108. double x3. } r3=r2*Math. for(int i=0.PI*a3/180). x2+(x3-x2)*k.i++){ k=(double)i/n. r2*Math.cos(Math.sin(Math.cos(Math. drawStarPoint(rg. r2*Math.PI*a3/180).cos(Math. double x1. r3*Math.10).cos(Math. rg.sin(Math. seteaza culoarea de desenare neagra si genereaza din figura apeland de mai multe ori metoda drawStarPoint(). Generarea si afisarea desenului se face in metoda paint() a clasei StarPicture.PI*a3/180). } } } 285 Programul de mai sus creaza un obiect rg din clasa RealGraphics definita de noi anterior si il foloseste pentru desenarea imagini din figura 23.0.2.sin(Math.10).10).PI*a1/180). pe . Metoda sterge bufferul imagine a lui rg. r2*Math. r2*Math.cos(Math. r2*Math.sin(Math. } for(int i=0.cos(Math.int n) { double k. a3=a2+36.double y3.sin(Math.PI*a1/180). drawStarPoint(rg.sin(Math.PI*a1/180).r1*Math.i<5.r1*Math.sin(Math.i<=n. r1*Math. drawStarPoint(rg.sin(Math.0. r2*Math. r1*Math.cos(Math.PI*a3/180).cos(Math.drawLine(x1+(x2-x1)*k.sin(Math.cos(Math.PI*a1/180). Desenarea se face intr-un buffer intern al lui rg.10). r2*Math. drawStarPoint(rg.PI*a2/180). a2=a1+36. a2=a1+36. subclasa a clasei Canvas.i<5.10).PI*a3/180).PI*a3/180). r3*Math.PI*a1/180). r2*Math.i++){ a1=i*72.r3*Math.sin(Math.PI*a2/180).r1*Math.Note de curs a1=i*72. r3*Math. rg.double y2.PI*a1/180). double x2.0. r1*Math.double y1.PI*a1/180).PI*a1/180).PI*a1/180).cos(Math.

Solutia o reprezinta insarcinarea unui thread separat cu generarea imaginii. ca in exemplul urmator.awt. class Star extends Frame{ .a1)(aflat pe cercul de raza r1) iar d2 uneste acest punct de un punct de coordonate polare (r2. Acesta va face toate transformarile necesare. metoda paint() “extrage” din obiectul rg acest buffer-imagine invocand metoda getImage() a claseiRealGraphics si il deseneaza pe suprafata componentei starPicture.. q1.pn iar pe dreapta d2 punctele echidistante q0. .. Dupa ce intreg desenul a fost generat.a2) )(aflat pe cercul de raza r2). Se unesc perechile de puncte (pi. Trasarea segmentelor de dreapta se face in planul real folosind pentru desenare obiectul rg din clasa RealGraphics. Dreapta d1 uneste centrul cercului cu un punct de coordonate polare (r1..23. Amble segmente se impart in acelasi numar n de semente egale. . p1.286 CURS 23 langa alti parametri si referinta la obiectul rg pentru desenare.0)) Valorile coordonatelor sunt valori reale si se calculeaza ca proiectii ale punctelor pe abscisa si ordonata folosind functiile trigonometrice sin() si cos() implementate de clasa Math. Utilizarea unui thread separat pentru animatie In exemplul precedent toate operatiile de calcul necesare trasarii graficului sunt efectuate de threadul AWT. rezultand pe dreapta d1 punctele echidistante p0. Pe perioada efectuarii calculelor si trasarii graficului thredul nu va putea procesa evenimentele interfetei grafice. Punctul q0 este identic cu pn iar qn se afla pe cercul de raza r2.. Aceasta este un dezavantaj serios daca volumul de calcule este mare si deci necesita un timp indelungat. threadul AWT urmand doar sa o afiseze in cadrul metodei paint().*. Metoda drawStarPoint() deseneaza in bufferul imagine o figura realizata prin trasarea a mai multor linii pe baza urmatorului algoritm: Fig. la fel cum fotograful scoate filmul din aparat. import java. Punctul p0 se afla in centrul cercului iar pn pe cercul de raza r1. generand desenul in bufferul-imagine. Coordonatele punctelor pi si qi se calculeaza relativ la un sistem de coordonate xOy carteziene cu originea in centrul cercului (punctul p0 are coordonatele (0.qn.qi) prin segmente de dreapta rezultand un colt al stelei desenate de program.3 – desenarea unui colt al stelei Coltul stelei este format din doua segmente de dreapta d1 si d2.

360).r3.r1*Math.starPicture). r1*Math. add("Center".film=new Thread(win.WINDOW_DESTROY){ hide(). return true. }else if(ready){ g. } } private void drawStar(int phi) { double r1=120.400).PI*a1/180).sin(Math.cos(Math. drawStarPoint(0.PI*a2/180).setDaemon(true).Note de curs private StarPicture starPicture.sin(Math. private boolean firstTime=true.setBackground(Color. public void initStarPicture(){ rg=new RealGraphics(-120. ready=false. dispose(). rg.i<5.PROGRAMARE IN JAVA .film. starPicture. win. System. starPicture=new StarPicture().r2=45. firstTime=false.240.0.10).handleEvent(e). } } class StarPicture extends Canvas implements Runnable{ private RealGraphics rg. 287 .black).0. a2=a1+36. rg.setColor(Color.a3.r1*Math. resize(400.height. } return super.0. public Star(){ super("Real Graphics"). private Thread film. drawStarPoint(0.sin(Math.360. win.white). win.d.this.PI*a1/180).film.a1.exit(0).i++){ a1=i*72-phi.d.drawImage(rg.-120. if(firstTime){ initStarPicture().a2.clear(). } public void paint(Graphics g){ Dimension d=size(). for(int i=0.getImage().width.240.0.PI*a2/180).this).cos(Math. ready=false. r2*Math. show().PI*a1/180). r2*Math. a3=a1-36. private int phi=0. } public static void main(String[] args){ Star win=new Star().id==e. } public boolean handleEvent(Event e){ if(e.start(). private boolean ready=true.starPicture).

cos(Math.PI*a1/180).PI*a1/180).10). rg. ready=true. a2=a1+36.sleep(100).0. double x3. } r3=r2*Math.cos(Math. phi%=360.PI*a1/180).PI*a2/180).sin(Math. a3=a2+36. r2*Math.PI*a1/180).i++){ k=(double)i/n.y1+(y2-y1)*k.y2+(y3-y2)*k).int n) { double k.PI*a3/180)..} } .cos(Math. r2*Math. try{ Thread.PI*a2/180).0.PI*a3/180).sin(Math.cos(Math.10).sin(Math. } repaint().PI*a2/180). drawStarPoint(r1*Math.0. r1*Math.sin(Math.){ if(!ready){ phi+=10.cos(Math. a2=a1+108.i++){ a1=i*72-phi.PI*a2/180). r3*Math.double y2.i++){ a1=i*72-phi.PI*a3/180).PI*a3/180). r3*Math. } } private void drawStarPoint(double x1. } } public void run(){ for(. r2*Math.double y1.PI/5).PI*a1/180). a3=a1-108. double x2.cos(Math. } for(int i=0. r3*Math.PI*a3/180). drawStarPoint(r1*Math.PI*a3/180). r2*Math.PI*a1/180).cos(Math.10).PI*a1/180).sin(Math. drawStarPoint(r3*Math. drawStar(phi).i<=n.cos(Math. r1*Math.0. for(int i=0.288 CURS 23 r1*Math.i<5.sin(Math. for(int i=0. r2*Math. x2+(x3-x2)*k. } catch(InterruptedException e){} } } public void update(Graphics g){ paint(g).cos(Math.sin(Math.cos(Math.sin(Math. r2*Math. r2*Math.double y3.drawLine(x1+(x2-x1)*k.i<5. r2*Math.10).

atribuind in acelasi timp valoarea false flagului ready. In aceasta situatie. Retele locale de calculatoare Asa cum doua sau mai multe threaduri pot coopera pentru rezolvarea unei probleme. fara stergerea prealabila a suprafetei de desenare.Note de curs 289 Deosebirea de programul anterior consta in faptul ca am declarat clasa StarPicture ca implementand interfata Runnable si am definit in cadrul ei metoda run(). accesul la canalul de comunicatie trebuieste sincronizat. Accesul la canalul de transmisie a . Intrucat timpul de asteptare estegenerat aleator aleator. este putin probabil ca doua calculatoare sa genereze aceeasi intarziere si sa intre din nou in coliziune. toate celalalte calculatoare care vor sa transmita si ele asteapta eliberarea cablului (terminarea transmisiei). cand doua sau mai multe calculatoare constatand eliberarea canalului de comunicatie incep sa transmita simultan. Fig. redeseneaza ciclic in bufferul imagine steaua din figura 23. De asemenea trebuieste rezolvata problema coliziunii. fiecare calculator este echipat cu un modul de comunicatie numit interfata de retea.4 este prezentat un exemplu de interconectare a calculatoarelor intr-o retea locala Ethernet. Pe de alta parte threadul AWT afiseaza imaginea pe suprafata componentei. calculatoarele pot fi intrerconectate intre ele fie local. In figura 23.23. Pentru transmiterea de date. tot asa si doua sau mai multe aplicatii ruland pe calculatoare diferite conectate printrun canal de comunicatie pot sa interschimbe date intre ele.2 rotind-o la fiecare iteratie cu 10 grade (variabila phi este incrementata cu acest pas) dupa care apeleaza repaint().4 Retea locala de calculatoare Intrucat toate calculatoarele sunt conectate pe un singur cablu coaxial. sesizand coliziunea ele vor inceta transmisia si vor astepta un interval de timp aleator dupa care vor incera din nou sa transmita datele. Activitatea celor doua threaduri este sincronizata prin flagul ready. transmitand date. In consecinta putem sa cream un thread care sa aibe acces in timp ce executa metoda run() la datele obiectului StarPicture starPicture printre altele si la RealGraphics rg. threadul film incepe redesenarea figurii numai cand flagul ready are valoarea false. Cand acest flag are valoarea true threadul AWT stie ca imaginea este gata si deci o obtine apelaind metoda rg. Metoda update() este supradefinita pentru a apela direct metoda paint(). Metoda run()executata de threadul film. Toate calculatoarele sunt conectate prin intermediul acestor module la un cablu coaxial care asigura transmisia datelor intre ele. Pe de alta parte. Astfel daca unul din calculatoare a ocupat cablul.PROGRAMARE IN JAVA . Pentru aceasta. fie printr-o retea de comunicatii.getImage() si o afiseaza.

adresand anumite porturi cu o anumita adresa. Implementarea functiilor de catre driver tine insa seama de specificul modulului.23. si un cod suma ciclica de control CRC (Cyclic Redundancy Checksum)generat pe baza datelor expediate(adrese. Inerfata se ocupa de impachetarea si transmiterea blocului de date. Comunicatia intre doua module de retea se desfasoara astfel.5). Modulele hardware sunt livrate de producator insotite de driverele aferente. astfel ca in retea nu pot exista doua module cu acelasi cod de identificare. . programul care a solicitat transmiterea datelor este liber sa se ocupe de altceva. Fiecare modul de retea are un numar de serie unic. In tot acest timp. pe un alt calculator din reteaua locala (conectat la acelasi cablu de date printr-o interfata de retea similara) poate fi executat un program care indeplineste functia de destinatar (de exemplu functia lui poate fi sa afiseze datele receptionate din retea). Fig. Toate modulele din retea sunt legate la acelasi cblu astfel incat au acces la toate pachetele de date care sunt transmise pe cablu.5 – structura pachetului de date La receptie. Acest numar serveste ca adresa a modulului in reteaua locala. La tratarea intreruperii programul va prelua blocul de date si va reveni la activitatea curenta.lungime blc de date si blocul de date propriuzis)(figura 23. avand un set de comenzi diferit. Solutia consta in utilizarea unor module software numite drivere care ofera o interfata standard in comunicatia dintre programe si modulele de retea. etc. asteptand eliberarea liniei. ea genereaza o intrerupere a activitatii curente a programului acesta fiind astfel atentionat ca poate sa solicite transmisia unui nou bloc de date. Asa cum o scrisoare inainte de a fi expediata este introdusa intr-un plic pe care se scrie peo fata adresa destinatarului iar pe cealalta fata adresa expeditorului. evident ca el nu va mai comunica corect cu modulul si deci nu va functiona corect. Pentru a dialoga cu modulul de retea.290 CURS 23 datelor si rezolvarea coliziunilor este rezolvata pe cale hardware chiar de catre interfetele de retea. adresele modulului expeditor si a modulului destinatar. Acest program este intrerupt din activitatea curenta de catre interfata de retea in momentul in care aceasta a receptionat un bloc de date expediat de intrfata de retea a unui alt calculator. pachetul este retransmis. Daca un astfel de program va fi executat pe un calculator echipat cu o interfata de retea a unui alt producator. Interfetele de retea sunt module inteligente care pot fi comandate de un program prin inscrierea unui cuvant de comanda intr-unul din porturile prin care modulul este conectat la magistrala de date. Programele trebuiesc proiectate sa fie cat mai independente de structura hardware a calculatoarelor pe care urmeaza sa fie instalate. datele sunt “impachetate” adaugandu-li-se informatii suplimentare cum ar fi un antet. programele apeleaza functiile standard de citire/scriere/configurare oferite de driver. Daca CRC-ul calculat la receptie nu coincide cu cel din pachet. inscriind cuvintele de comanda corespunzatoare si datele la porturile modulului astfel incat sa realizeze operatia solicitata. rezolvand eventualele coliziuni. dimensiunea blocului de date. Programatorul nu trebuie sa cunoasca amanunte privind arhitectura hardware a placii. Programul poate sa transmita interfetei un bloc de octeti (date) pentru a fi expediati la destinatie. si fiind activate de o anumita intrerupere. Pe de alta parte. aceasta suma ciclica de control (CRC-ul) este folosita pentru verificarea integritatii pachetului. In momentul in care iterfata a reusit sa transmita datele. Problema cu acest model simplist de comunicatie este ca programele din acest exemplu sunt proiectate sa dialogheaza cu un anumit tip de module hardware comandate printr-un set de coduri de comanda specific.

PROGRAMARE IN JAVA . O astfel de retea este constituita din mai multe calculatoare interconectate prin legaturi punct-la-punct astfel in cat fiecare calculator este legat de doua calculatoare vecine cu cite o legatura punct-la-punct rezulta structura inelara (ring) din figura 24. . si cutia-token este goala(tokenul este liber) il va depune in cutie si o va transmite mai departe.Note de curs 291 Curs 24 Retele de tip Token Ring In continuare este prezentat un mecanism de comunicatie in retea total diferit de cel dat ca exemplu in cursul precedent(Ethernet). de la un calculator la altul.1.24. Daca un calculator are de transmis altuia un mesaj. Cand cutia ajunge la destinatar acesta isi citeste mesajul si il marcheaza corespunzator.1 Retea Token Ring Din cele 4 calculatoare din aceasta figura are dreptul sa transmita calculatorul care a receptionat un pachet de date special numit token. Am ales pentru aceasta modelul de retea Token Ring. Tokenul poate fi deci asemuit cu o cutie care se transmite din mana in mana. Acesta extrage mesajul din cutie verificand daca este marcat de destinatar. Fig. avand astfel confirmarea de primire. Cutia goala o va transmite mai departe pentru a fi folosita de celalalte calculatoare din retea pentru transmiterea altor mesaje. Dupa aceasta transmite cutia cu mesajul marcat mai departe pana ajunge inapoi la expeditor.

. va calcula si adauga CRC-ul pachetului si va transmite tokenul astfel construit calculatorului vecin B. ii va calcula CRC-ul si il va compara cu CRC-ul inscris in token si va seta un flag E (Eroare) in 1 daca cele doua valori nu sunt identice. In concluzie. “ascultand” linia pentru a sesiza inceputul transmisiei tokenului. primind si procesind informatia continuta de token. el va astepta sa primeasca un token liber. Daca calculatorul vecin nu este pe receptie. o alta statie sesizand eroarea. In acest caz releul de bypass este dezexcitat. si contactul sau inchis. Sa presupunem ca el are de transmis un bloc de date unui alt calculator (sa zicem calculatorului D). In aceste conditii el va trece in regim de receptie in care nu numai va transmite ma departe tokenul dar. aflat in starea de ascultare. D va receptiona tokenul. in plus va stoca in memorie pachetul primit pentru a extrage blocul de date transmis de A. Daca tokenul este ocupat (T=0). AC=10 – adresa a fost recunoscuta dar datele nu au fost copiate in memoria destinatarului. Constatand ca destinatarul nu este el. Daca tokenul este liber (T=1)si calculatorul nu are de transmis nimic.292 CURS 23 Pachetul token are in structura sa un flag numit T. il va citi si va constata ca urmeaza sa primeasca niste date de la A. chiar daca calculatorul are ceva de transmis. In momentul in care calculatorul care asculta sesizeaza prezenta semnalului de transmisie pe linie el trece in starea de receptie. Astfel tokenul va calculatorului urmator din inel care asculta linia asteptand inceputul transmisiei unui token. il transmite urmatorului calculator din inel. ajungand la D. un calculator dintr-o astfel de retea se poate afla in una din cele patru stari: ¾ transmisie ¾ ascultare ¾ bypasat (oprit) ¾ receptie date Daca unul din calculatoare (de exemplu A) tocmai a receptionat de la calculatorul vecin D tokenul liber (T=1). Astfel ca se limiteaza sa transmita tokenul calculatorului vecin care se afla in asteptare. In acest caz. va inscrie in token adresa sa si adresa destinatarului (de exemplu calculatorul D). Calculatorul B. Daca flagul E=1 inseamna ca datele au ajuns cu bine la destinatar si au fost copiate in memorie si au fost alterate ulterior. va trimite mai departe tokenul calculatorului vecin. Semnalul purtator de informatie va trece astfel de calculatorul C pe linia vecina. si va constata ca este ocupat si va vedea daca nu cumva el este cel care urmeaza sa primeasca date. A va seta bitul T in 0 (tokenul devenind un token ocupat). Daca este 0 tokenul este ocupat. Aceasta situatie apare atunci cand destinatarul este oprit. Sa presupunem ca acesta (C) este oprit. Inainte de a transmite tokenul mai departe va seta un flag corespunzator urmatoarelor situatii: ¾ adresa recunoscuta – flagul A ¾ Pachetul copiat – flagul C ¾ Eroare – flagul E In final tokenul va ajunge la emitent – calculatorul A. va primi tokenul. Acesta va examina strea flagurilor tragand concluziile corespunzatoare: AC=00 – adresa destinatarului nu a fost recunoscuta de nici o statie si deci datele nu au fost copiate de destinatar in memorie. Daca acest bit are valoarea 1 inseamna ca tokenul este liber. daca flagul E=1. Inainte de a-l trimite mai departe. fiind oprit. inseamna ca motivul refuzarii datelor il constitue altwerarea pachetului (CRC –ul calculat nu coincide cu cel inscris in pachet). Daca E=0 motivul este necunoscut. AC=11 Adresa a fost recunoscuta si datele au fost copiate in memoria destinatarului. el este bypasat hardware de contactul inchis al unui releu care sesizeaza disparitia tensiunii de alimentare. va adauga blocul de date .

2 – structura pachetului token In timpul functionarii. Desi aparent toate calculatoarele din retea sunt egale. Ea nu va mai transmite tokenul si deci celalalte statii din retea vor astepta degeaba sa-l primeasca. In acest moment. unele dintre acestea sunt mai egale decat altele. Astfel. la initializarea retelei este desemnat sa joace rolul de monitor activ al comunicatiei (Active Monitor).Note de curs 293 Daca AC=01 inseamna ca o alta statie decat destinatarul a copiat neautorizat datele in memoria sa. pe langa functiunile descrise mai sus unul din calculatoare. acesta nu ajunge din nou la monitor. Fig.2. elaborand si transmitand mai departe un token liber pentru a permite si altor statii sa transmita date. In aceasta calitate el marcheaza un token ocupat care trece prin dreptul sau prin setarea unui flag M din structura acestuia in starea 1(expeditorul blocului din date din token pozitioneaza acest flag in 0 inainte de a trimite tokenul spre destinatie).PROGRAMARE IN JAVA . Daca monitorul activ va receptiona a doua oara acelasi token ocupat el isi va putea da seama dupa starea flagului M=1 ca aceasta este deja a doua a “calatorie” a datelor si deci dintr-un motiv sau altul expeditorul sau nu a reusit sa il elibereze(fiind probabil oprit). In consecinta el genereaza si trimite in retea un nou token care sa-l inlocuiasca pe cel pierdut. Pe de alta parte monitorul activ cronometreaza timpul scurs din momentul in care a expediat un toke. Deci oricare din statiile din retea poate prelua aceasta functie daca calculatorul care o indeplineste la un moment dat este oprit. Astfel sunt definite in retea calculatoarele care vor inlocui monitorul activ in cazul deconectarii acestuia. liber pe care il va transmite spre calculatorul vecin. In aceste conditii tokenul va circula la infinit intre celalalte statii ale retelei fara a mai fi elibert de niciuna dintre ele. acesta va considera ca tokenul s-a pierdut pe traseu fiind “inghitit” de zgomotul retelei sau in urma deconectarii unei statii inainte ca aceasta sa il transmita mai departe. Este sarcina statiei A care a adaugat blocul de date in token sa le si extraga. Structura unui pachet token este redata in figura 24. O alta situatie de avarie este oprirea statiei care a transmis un token ocupat de un bloc de date catre o alta statie din retea si a fost oprita inainte de a apuca sa extraga datele si sa elibereze tokenul. in reteaua Token Ring pot aparea evenimente care perturba functionarea mecanismului descris mai sus. De exemplu daca una din statiile retelei este oprita in momentul in care detine tokenul. In ambele cazuri comunicatia in retea este blocata.24. Daca dupa un anumit interval de timp TRT (Token Rotation Time) considerat ca fiind suficient ca un token sa efectueze o calatorie completa in inelul retelei (de exemplu 10 microsecunde). monitorul activ intervine oprind tokenul “orfan” si construind unul nou. Pentru a preantampina aceste fenomene mecanismul de comunicatie in reteaua de tip Token Ring prevede proceduri de detectare a evenimentelor de mai sus si de restabilire a functionarii normale a comunicatiei. Ce se intampla insa daca calculatorul care indeplineste functia de monitor activ este oprit? Functia de monitor activ nu ridica cerinte hardware speciale pentru calculatorul care o indeplineste. Statiile din aceasta “rezerva de cadre” se numesc monitoare standby .

care sa poata comunica intre ele daca respecta standardul respectiv. Va deveni activ monitorul standbay cu adresa cea mai mare. Monitoarele standby receptioneaza pe rand acest pachet care le confirma ca monitorul activ functioneaza. . el se va retrage din cursa. Deci daca un monitror standby a receptionat un pachet CL_TK cu adresa expeditorului mai mare decat adresa proprie. Protocoalele de comunicatie sunt standardizate pentru a permite producatorilor de hardware diferiti sa produca module compatibile. La randul lor. Va face acelasi lucru pentru pachetele din reteaua B facandu-le sa ajunga in reteaua A. monitoarele standby isi confirma prezenta in retea emitand periodic pachete SMP (Standby Monitor Present). Interconectarea a doua retele locale diferite Analizand cele doua exemple de retele vom putea trage urmatoarea concluzie. unul din monitoarele standby se va sesiza si va solicita preluarea postului de monitor activ prin trimiterea periodica a unor pachete de control CL_TK (Claim Tocken). atunci cand inretea nu circula un token continand date. Criteriul de promovare in functia de monitor activ este adresa.3 iar protocolul Token Ring in IEEE 802. tot asa nu este posibila comunicatia intre calculatoarele unei retea fara existenta si respectarea acestui set de reguli care includ definirea structurii unui pachet de date. modul de adresare al pachetelor. pierderea tokenului. Comunicatia intre calculatoarele unei retele se desfasoara pe baza unui set de reguli foarte precise. Monitorul standby continua sa trimeata acest pachet pana cand : ¾ va primi un pachet CL_TK cu adresa expeditorului mai mare decat adresa proprie. Se va prevedea un nod comun intre cele doua retele – un calculator care va fi echipat cu doua interfete de retea – una de tip A si celalta de tip B. existand un candidat mai potrivit. Un astfel de calculator se numeste Bridge – jucand intr-adevar rolul de punte pentru circulatia mesajelor intre cele doua retele (figura 24. ¾ va primi un pachet de control PURGE emis de monitorul standby care a castigat concursul constatand ca nu exista in retea un alt monitor standby cu adresa mai mare si s-a auto-promovat in consecinta monitor activ.3). modul de rezolvare al avariilor cum ar fi coliziunile. Astfel protocolul Ethernet este definit in standardul IEEE 802.5 Se pune problema urmatoare: O institutie dispune in aceeasi cladire de doua retele A si B de tipuri diferite. monitorul activ genereaza periodic (de exemplu la fiecare 7 secunde) un pachet de control numit AMP (Active Monitor Present). Daca monitorul activ intarzie sa trimeata pachetul AMP. etc. Ce poate fi facut pentru a asigura comunicatia dintre o statie oarecare a retelei A cu o alta statie a retelei B? La prima vedere rezolvarea este destul de simpla.294 CURS 23 (Standby Monitors). Asa cum nu este de imaginat traficul autovehiculelor intr-un oras aglomerat fara respectarea regulilor de circulatie. modalitatile de acces la canalul de date. mecanismul de validare al datelor. Acest ansamblu de reguli se numeste Protocol de comunicatie. Pe acest calculator va rula un program specializat care va avea sarcina sa detecteze pachetele de date din reteaua A sa le despacheteze din “plicul” original acceptat de protocolul din reteaua A si sa le impacheteze in formatul acceptat de protocolul retelei B si sa le depuna pe canalul de date al retelei B. Pentru ca monitoarele standby sa poata detecta disparitia sa.

De data aceasta va trebui sa apelam la serviciile unei retele de comunicatii (cel mai frecvent publice dar sunt cazuri cand este folosita o retea de comunicatii privata – cazul sistemelor de transfer bancar sau al sistemelor informatice militare).4 – Interconectarea a doua retele locale la distanta daca dorim ca legatura intre cele doua retele sa fie permanenta. Rezolvarea problemei a fost inspirata din functionarea sistemelor postale cu transmiterea din host in host a pachetelor pe o anumita ruta stabilita in functie de adresa destinatarului.24.24. Daca una din rute nu este disponibila. stabilesc prin linia de comunicatie o legatura punct-la-punct si pot juca rolul de bridge intre cele doua retele.3 – intrconectarea a doua retele locale diferite printr-un bridge Sa analizam acum cum se modifica problema daca vrem sa interconectam doua retele locale aflate in cladiri diferite aflate orase diferite.4 Fig. .PROGRAMARE IN JAVA . numite calculatoare gazda (host).Note de curs 295 Fig. ea trebuie realizata printr-o linie telefonica inchiriata. In acest caz legatura intre retele trebuie facuta printrun modem ca in figura 24. Totusi aceasta solutie devine greoaie si nesigura in cazul interconectarii mai multor retele locale. Daca una din liniile de comunicatie se defecteaza reteaua formata prin interconectarea mai multor retele locale este fragmentata in doua subretele astfel incat pachetele de date dintr-o subretea nu mai ajung si in cealalta. Aici calculatoarele echipate cu modem.

daca un calculator din reteaua A trebuie sa transmita un pachet de date unui calculator din reteaua B.24. va alege o alta ruta.5 Transmiterea pachetelor cu de date cu ajutorul ruterelor In cazul din aceasta figura.5. Ele sunt interconectate prin canale de comunicatie inchiriate de mare viteza care asigura posibilitatea transferului rapid a unui volum urias de date (cabluri cu fibre optice. Ruterele formeaza o retea de hosturi ca cea din figura 24. respectiv transmitandu-l hostului B. Un calculator host care realizeaza functia de rutare a pachetelor de date se numeste dupa cum banuiti ruter (router). canale satelit. Daca insa comunicatia intre hostul A si hostul B nu functioneaza. Fig. poate mai lunga.296 CURS 23 hostul care detine la un moment dat pachetul. hostul A va hotara ca pachetul sa fie transmis la destinatie pe ruta cea mai scurta. Adresa hardware a acestuia specificata in . hostul A va trimite pachetul pe ruta a doua. etc). Problema care apare la rutarea pachetelor consta in determinarea rutei spre reteaua de destinatie pe baza adresei destinatarului. dar in schimb disponibila. spre hostul B. Acesta va ruta pachetul spre C care il va transmite in reteaua locala C spre calculatorul de destinatie.

.Daca cel mai semnificativ bit al adresei (bitul 31) este 0 inseamna ca este vorba de o retea mare din clasa A.clasa A in care netid este reprezentat pe 8 biti (1 octet).6. intr-o singura retea. Deoarece ruterul “poarta de iesire” (gateway) din reteaua locala a pachetului il va despacheta. dupa cum am mai spus. Deci urmatorii 7 biti vor identifica reteaua iar restul de 24 claculatorul. a cate 16. S-a adoptat urmatoarea conventie: .6 Structura unui bloc de date tip datagrama Datagrama incapsuleaza deci alaturi de informatia utila adresele logice ale expeditorului si destinatarului. adrese diferite la 224 = 16.Note de curs 297 campul MAC (Media Access Control) corespunzator al pachetului este.777. adrese diferite la 28 = 256 calculatoare. 24. Pentru ca blocul de date sa poata fi rutat el trebuie sa contina adresele logice ale expeditorului si destinatarului precum si alte informatii cum ar fi lungimea sa in octeti. Componenta netid este un numar reprezentat pe N biti care identifica reteaua iar hostid este un numar reprezentat pe restul de 32-N biti si identifica calculatorul gazda (host) din reteaua respectiva.777. fiecare calculator va primi o adresa unica in reteaua logica globala constituita prin interconectarea retelelor locale. Adrese din clasa C se folosesc pentru retelele mici (cu numar mic de calculatoare). Vom putea astfel asigna. Vom putea astfel interconecta intr-o retea logica 27 = 128 de retele mari. adrese diferite la 216 = 65.536 calculatoare.PROGRAMARE IN JAVA . un numar arbitrar care desi identifica unic calculatorul intr-o retea locala nu contine informatie care sa permita ruterului sa stabileasca despre care dintre cele 4 posibile este vorba. ¾ adresa logica are doua componente: {netid. In acest caz vom dispune de restul de 8 biti pentru a defini adresele calculatoarelor din retea.216 calculatoare. Un astfel de bloc il vom numi in continuare Datagrama. Adrese din clasa A se folosesc pentru retele mari (cu numar foarte mare de calculatoare). ¾ In conditiile punctului de mai sus vom avea patru clase de adrese: .clasa B in care netid este reprezentat pe 16 biti (2 octeti). Vom putea astfel asigna. ¾ Dispunand de un numar pe 32 de biti nu putem sa delimitam partea care desemneaza netid de partea care desemneaza hostid daca nu exista un indicator din care sa ne dam seama carei clase de retele apartine adresa respectiva. intr-o singura retea. Adrese din clasa B se folosesc pentru retele medii (cu numar mediu de calculatoare). Solutia este de a organiza calculatoarele din retelele locale interconectate intr-o retea logica globala. In acest caz vom dispune de restul de 24 de biti pentru a defini adresele calculatoarelor din retea. instituind un sistem unitar de adresare a acestora.216 calculatoare fiecare. intr-o singura retea.clasa B in care netid este reprezentat pe 24 biti (2 octeti). . Fig. In acest caz vom dispune de restul de 16 biti pentru a defini adresele calculatoarelor din retea.hostid}. In concluzie blocul insusi va avea o structura de genul celei din figura 24. . ce se transmite de la o retea la alta de la ruter la ruter este doar acest blocul de date. Astfel. Adresele logice se stabilesc tinand cont de urmatoarele considerente: ¾ adresa logica este un numar reprezentat pe 32 de biti (4 octeti). Vom putea astfel asigna. extragind blocul de date ceea.

acesta o va impacheta in formatul specific retelei locale respective si va transmite pachetul spre calculatorul de destinatie. ¾ Dupa componenta netid a adresei. va determina carui ruter trebuie sa o trimita mai departe si o va transmite acestuia. Vom putea astfel interconecta intr-o retea logica.ul reprezentat pe 16 biti.Daca bitii 31 si 30 au valoarea 11 iar bitul 29 este 0 este vorba despre o retea mica din clasa C cu netid. La adresa hardware a expeditorului va figura adresa interfetei sale cu aceasta retea. Restul de 16 biti ai adresei vor contine hostid-ul claculatorului. Pentru destinatar insa ruterul va trebui sa determine adresa hardware a acestuia din reteaua locala pe baza adresei globale din datagrama.536 calculatoare fiecare. ¾ Daca datagrama nu este adresata retelei locale deservite de ruter el va consulta tbela de rutare. Restul de 8 biti ai adresei vor contine hostid-ul claculatorului. va cauta in tabela de rezolutie a adresei adresa hardware asociata adresei logice a destinatarului. a cate 256 de calculatoare fiecare. Daca datagrama este adresata retelei deservite de el. . alaturi de cele maximum 128 de retele mari. Datagrama adresata unui calculator din reteaua cu identificatorul netid va fi trimisa catre ruterul asociat in tabela de rutare. O ruta asociaza unui identificator netid al unei retele cu ruterul catre care trebuie trimisa datagrama ca sa ajunga la reteaua de destinatie. ruterul dtermina daca destinatarul este in reteaua locala deservita de el sau daca trebuie sa ruteze datagrama mai departe. Daca primii doi biti din cei 16 au valoarea 10 desemnand clasa retelei. . Cu aceasta inca problema nu este definitiv rezolvata. Vom putea astfel interconecta intr-o retea logica. inca 221 = 2. Procesul continua pana cand datagrama va ajunge la ruterul poarta de intrare in reteaua local careia ii apartine calculatorul destinatar. In aceste conditii activitatea ruteruluiului se va desfasura astfel: ¾ Ori de cate ori receptioneaza o datagrama. Aceasta tabela poate fi definita manual – de exempolu editata intr-un fisier. ceilalti 21 de biti vor identifica reteaua.152 de retele mici. acesta va citi tabela de rezolutie a adreselor din fisier in memorie si o va accesa ori de cate ori detecteaza un pachet de date care trebuie transbordat.097. Faptul ca am asociat fiecarui calculator din retea o adresa unica nu inseamna ca am raspuns la intrebarea – ce va inscrie in campurile de adresa hardware (campurile MAC– Media Acess Control) ale noilor pachete la reimpchetarea blocului de date? Este clar ca in campul expeditorului. ruterul va inscrie propria sa adresa hardware din reteaua respectiva.384 retele medii. In acest scop el detine o tabela de corespondenta a adreselor in care sunt definite perechile adresa globala – adresa hardware. ¾ Impacheteaza datagrama conform protocolului retelei deastrvite si o expediaza in reteaua locala de destinatie pe adresa hardware gasita la pasul anterior.384 de retele medii.ul reprezentat pe 24 de biti. La initializarea ruterului. Pe baza unei astfel de adrese ruterul va putea sa identifice reteaua de destinatie a datagamei. Daca primii trei biti din cei 24 au valoarea 110 desemnand o retea din clasa C. el citeste din aceasta adresa logica a destinatarului. 214 = 16. a cate 65. Cand datagrama ajunge la ruterul poarta de intrare in reteaua de destinatie. va determina catre ce ruter trebuie transmisa datagrama in continuare si o va transmite acestuia.298 - CURS 23 Daca bitul 31 este 1 si bitul 30 este 0 este vorba despre o retea medie din clasa B cu netid. Acesta la riandul sau va consulta tabela proprie de rutare. ceilalti 14 biti vor identifica reteaua. alaturi de cele maximum 128 de retele mari si cele 16. El dispune de o tabela de rutare ale carei intrari contin fiecare cate o ruta.

Acest protocol se bazeaza insa pe protocoalele de comunicatie de la nivelul legaturii de date cum ar fi Ethernet. un program care are de transmis date unui alt program care ruleaza pe un alt calculator va solicita modulului software care implementeaza protocolul IP sa transmita mesajul respectiv specificandu-i doar adresa logica a destinatarului. un mod de adresare in reteaua logica. 3. Ruterul va extrage din campul de adresa expeditor al pachetului ARP Reply primit adresa hardware cautata si o va inscrie in campul de adresa destinatar al pachetului generat si il va expedia in reteaua locala. Sa existe doua sau mai multe calculatoare in retea care sa aiba aceiasi adresa logica.PROGRAMARE IN JAVA . 2. reprezentand o cerere de rezolutie de adresa (pachetul este numit ARP request – Address Resolution Protocol request). Astfel acelasi modul software care implementeaza acest protocol va putea fi rulat si pe un PC intr-o retea Ethernet si pe un PC intr-o retea Token Ring. un sofer care a condus toata viata numai automobile Lamborghini. poate pilota un Trabant si invers. Sunt posibile trei situatii. Analizand mecanismul de comunicatie descris mai sus constatam ca si aceasta se desfasoara dupa un set de reguli precis care defineste o structura a datagramei. Acest set de reguli constitue si el un protocol de comunicatie. Ruterul trimite in reteaua locala deservita de el un pachet de control de un tip special. (Este situatia similara celei de la automobile unde interfata este aceiasi si la un trabant si la Lamborghini – un volan. Oricand. 1. S-a gasit o solutie care elimina acest inconvenient. Destinatarul poate sa fie calculatorul pe . trei pedale si o maneta pentru schimbarea vitezelor. si pe un PC conectat pe o linie telefonica la un ruter printr-o legatura PPP. deoarece driverele acestor module de retea diferite ca constructie si principiu de functionare asigura o interfata standardizata cu programele utilizatoare ascunzand particularitatile hardware specifice fiecarui tip in parte. Pachetul este adresat tuturor calculatoarelor din reteaua locala (broadcast). Ruterul va primi mai multe raspunsuri ARP Reply. Calculatorul cu adresa logica specificata in pachet sa fie oprit. Protocolul discutat mai sus descrie structurile si regulile de manipulare a datelor pentru transmiterea lor in reteaua logica constituita din interconectarea retelelor fizice de tipuri diferite situate la distanta.Note de curs 299 Aceasta solutie prezinta un dezavantaj. La acest nivel. Ori de cate ori este adaugat un nou calculator in retea sau se inlocuieste interfata de retea a unui calculator (cu una mai performanta sau in urma defectarii interfetei vechi) tabelul de rezolutie a adresei trebuie actualizat. trimis pe adresa hardware a ruterului (aflata din campul de adresa hardware a expeditorului din pachetul ARP Request). Pachetul contine in blocul de date adresa logica a calculatorului a a carui adresa fizica ruterul doreste sa o afle. niste reguli precise de rutare a datagramelor si de rezolutie a adreselor hardware. Token Ring sau PPP (Point to Point Protocol) care descriu regulile de comunicatie intre interfetele de retea. Modulele software si programele care implementeaza acest protocol nu acceseaza direct interfetele de retea ci interactioneaza cu ele prin intermediul driverelor acestor interfete. Cu toate acestea hardware-ul de sub capota celor doua masini este foarte diferit. In campul de adresa hardware.) Spunem despre acest protocol ca este definit la nivelul retea logica (Network) si il putem amplasa pe o scara ierarhica ca fiind deasupra protocoalelor de la nivelul legaturii de date (Data Link). Calculatorul cu adresa logica specificata in pachet isi recunoaste adresa logica si raspunde cu un pachet ARP Reply. ruterul trece adresa hardwre a interfetei sale de retea. fara sa se preocupe de pozitia acestuia si de tipul retelei careia ii apartine. Situatia este ilegala dar este posibila. In acest caz ruterul va astepta un interval de timp prestabilit si daca nu primeste in acest interval de timp raspunsul abandoneaza pachetul.

300 CURS 23 care ruleaza el insusi. cablu coaxial sau fibra optica – sub forma de semnale electrice sau optice.24. calculatorul invecinat de pe aceiasi masa. Modulul software transmitator care implementeaza protocolul IP impacheteaza datele ce urmeaza sa plece de la calculatorul A intr-o datagrama si o paseaza prin intermediul driverului de de retea la nivelul legaturii de date. Protocolul IP asigura doar un singur canal de comunicatie intre A si B. Din ruter in ruter. Aplicatia A1 trimite mesaje aplicatiei B1 si A2 lui B2. Daca nu. el s-a numit Internetwork Protocol sau mai scurt Intrenet Protocol sau si mai scurt IP. Cu atat mai putin trebuie sa se preocupe programul expeditor de tipul placii de retea cu care este echipat calculatorul destinatar sau calculatorul propriu. transformandu-le intr-o singura retea logica prin introducerea unui sistem de adresare uniforma a calculatoarelor acestor retele.000 de kilometri distanta. Fig.7. Mesajul de la una din aplicatiile A1 sau A2 trebuie transmis de la calculatorul A la calculatorul B. un calculator aflat intr-un birou in aceiasi cladire sau un calculator aflat intr-o cladire situata in cu totul alt oras la 60. va cauta in tabela de rutare identificand ruta optima pe care va expedia datagrama. Pe motivul ca protocolul descris mai sus asigura comunicatia intre retele de tipuri diferite organizand calculatoarele din componenta acestora intr-o singura retea logica. La acest nivel datagrama este la randul sau impachetata de interfata de retea conform protocolului specific si depusa la nivelul fizic – perechi de fire torsadate. va extrage datagrama incapsulata in acesta.7 Comunicatia intre aplicatii concurente in reteaua IP In aceasta figura sunt reprezentata doua aplicatii “baieti” A1 si A2 care ruleaza concurent pe un calculator A si doua aplicatii “fete” B1 si B2 care ruleaza concurent pe un calculator B. adresa hardware de destinatie va fi cea a ruterulgateway al retelei locale care va prelua pachetul. Calculatoarele sunt interconectate printr-o retea IP. De fapt scopul inerconectarii calculatoarelor in retea este de a asigura comunicatia nu intre calculatoare ci intre aplicatii executate pe calculatoare diferite ca in figura 24. datagrama va ajunge la ruterul-gateway al retelei de . are doar sarcina sa ascunda caracterul eterogen din punct de vedere hardware si software al retelelor interconectate. Protocolul IP asa cum am vazut. va citi din datagrama identificatorul retelei de destinatie (componenta netid a adresei IP). Daca statia B se gaseste in reteaua locala pachetul de date va fi expediat pe adresa sa hardware gasita cu ajutorul protocolului de rezolutie a adresei. El nu ofera insa nici un mecanism de validare al integritatii datagramelor la receptie si nu rezolva nici accesul simultan la canalul de date al mai multor aplicatii concurente ruland pe acelasi calculator in regim multitasking.

Datorita rutarii (datagramele continand secvente ale mesajului pot ajunge la destinatie pe rute diferite si deci cu intarzieri diferite)ordinea de sosire a pachetelor poate sa fie diferita. Aplicatiile pot sa se conecteze la un astfel de port pentru a transmite sau receptiona date din canalul de comunicatie IP. transmitand continutul lui incapsulat intr-un pachet in care este specificat numarul portului expeditor si numarul portului destinatar. a doua sa ajunga prima iar a treia sa ajunga a doua mergand pe o ruta mai scurta decat prima. Datagrama este despachetata extragandu-se din ea informatia utila continand mesajul trimis de pe calculatorul A.PROGRAMARE IN JAVA . Canalul de date IP va fi interfatat cu un modul software prevazut cu un numar de “prize” numite porturi fiecare avand asociat un numar intreg ca identificator. poate sa ajunga la destinatie a treia. La scrierea de octeti intr-un port. desi a fost expediata prima. Aceasta va citi din buffer octetii mesajului din port. il completeaza la sfarsit cu un camp CRC calculat pe baza continutaului . Lungimea secventei este data de capacitatea bufferului portului. Pentru a iesi din acest impas s-a optat pentru solutia urmatoare. Acest pachet este pasat canalului IP care il va incapsula la randul lui intr-o datagrama si il va expedia pe canalul IP la destinatie. Astfel a secventa 2. Aici pachetul de date receptionat va fi despachetat extragandu-se datagrama care se paseaza modulului software receptor care implementeaza protocolul IP.Note de curs 301 destinatie. Nu se poate prevedea la scrierea unor rutine de serviciu ale sistemului de operare cum sunt modulele care implementeaza protocoalele de comunicatie in retea ce aplicatii vor apela la serviciile lor pentru transmiterea sau receptia unor mesaje. ea il va goli. Aici pacetul va fi extras din datagrama si pasat interfetei care va extrage din pachet datele si le va directa spre bufferul portul cu numarul specificat pe pachet la care asteapta aplicatia destinatar. Astfel datagrama continand prima secventa. el va fi trimis la destinatie sub forma mai multor pachete. Partial aveti dreptate dar apare aici o mare problema – aplicatiile. In aceste conditii pachetele continand secventele de mesaj trebuie sa contina un camp care sa specifice numarul secventei din mesaj continute. interfata care expediaza un pachet. in caz contrar trebuind sa astepte sosirea pe canalul IP a unei noi datagrame adresate portului). Datele receptionate trebuie sa ajunga la aplicatia B1 daca sunt expediate de A1 sau la B2 daca expeditorul este A2. Acesta va sesiza ca datagrama este adresata retelei sale locale si va face rezolutia adresei hardware dupa care va impacheta datagrama conform protocolului de la nivelul legaturii de date expediind-o spre calculatorul B. In momentul in care bufferul s-a umplut. spre deosebire de calculatoarele din retea nu pot fi caracterizate printr-o “adresa” fixa. Pe baza acestui numar secventele sunt “reasamblate” de interfata in ordinea corecta. interfata cu canalul IP mai implementeaza un mecanism care asigura o fiabilitate ridicata a canalului virtual de comunicatie intre doua porturi. Din experienta acumulata deja din descrierea protocoalelor probabil ca intuiti ca blocul de date care a fost receptionat si extras din datagrama trebuie sa fie la randul sau un “plic” avand inscriptionate pe el adresele expeditorului (A1 sau A2) si al destinatarului (B1 sau B2) si continand in interiorul sau mesajul transmis. O aplicatie poate inscrie octeti in portul respectiv sau extrage octeti din port ( numai daca sunt disponibili. Astfel. In tot acest timp aplicatiile B1 si B2 asteapta mesaje de la baietii din A. Daca mesajul este mai lung decat capacitatea bufferului. desi sosita prima nu va fi transmisa spre port pana cand nu este citita de aplicatia destinatar secventa 1 sosita a treia. Pe langa multiplexarea porturilor si reasamblarea pachetelor de date. fiecare pachet continand numai o secventa din mesaj. interfata nu ii expediaza imediat ci ii cumuleaza intr-un buffer de date. Aceste porturi se comporta ca niste streamuri de intrare la receptia si de iesire la transmisia de date.

Fig. interfata receptoare va genera si va trimite spre interfata expeditor un pachet de control care confirma primire pachetului de date. Protocolul descris a fost denumit Transmision Control Protocol sau mai scurt TCP. interfata ia decizia de retransmitere a pachetului pe care il considera pierdut. calculeaza CRC-ul acestuia si il compara cu valoarea din campul CRC primita.24. Daca dupa un interval de time-out nu primeste un astfel de pachet. Interfata care receptioneaza pachetul.8 .302 CURS 23 pachetului. In figura 24. Pe de alta parte. inseamna ca pachetul este valid si in consecinta. Acest protocol actioneaza la nivelul transportului de date fiind situat ierarhic deasupra protocolului IP. interfata expeditor asteapta receptia pachetului de confirmare a primirii sau cerere de retransmitere. In acest caz. In caz contrar va genera si trimite catre catre interfata expeditor un pachet de control prin care solicita retransmiterea pachetului de date. Din descrierea de mai sus a interfetei care creaza prin multiplexarea canalului IP si controleaza canale virtuale multiple pentru transportul datelor de la oaplicatie la alta constatam ca aceasta implementeaza o structura de date si un set de proceduri de comunicatie care constituie si ele un protocol.Stiva protocoalelor TCP/IP . considera ca acesta s-a pierdut pe traseu (de exemplu prin oprirea unui ruter care primise pachetul de date pentru rutare dar nu a mai apucat sa-l expedieze mai departe).8 este reprezentata stiva protocoalelor descrise mai sus si procesarile aplicate mesajului la transmiterea acestuia de la aplicatia expeditor la aplicatia destinatar. dupa ce a trimis un pachet de date. Daca cele doua valori sunt egale.

255. aceste valori fiind separate prin puncte: 141. acesta fiind rezervat pentru acest caz. Stiind adresele IP ale calculatoarelor din retelele mari din clasa A au bitul cel mai semnificativ 0 si deci adresele lor vor incepe cu un numar cuprins intre 1 ( primul octet al adresei este 00000001) si 126 (primul octet al adresei este 0111110) valorile 0 si 127 fiind rezervate.85.) ¾ {-1 -1} – adica 255.) ¾ {netid -1} – de exemplu 141.01010101.255.0. Un mesaj trimis pe o astfel de adresa va fi difuzat (broadcast) in reteaua locala specificata de netid.65. Aceasta adresa desemneaza reteaua locala si nu un calculator anume din retea.44. avand o semnificatie speciala.65. (Aceasta inseamna ca nici un calculator nu poate avea identificatorul 0.0.00000001.255. Adrese de IP cu semnificatie speciala O serie de adrese de IP sunt rezervate si nu desemneaza un anumit calculator dintr-o retea locala. (Aceasta inseamna ca nici un calculator nu poate avea identificatorul -1.65.00101100. Rezulta ca identificatorul calculatorului este 2. vom putea obtine acest identificator: 141. Sa luam un alt exemplu in care adresa IP a calculatorului este 195. Ele au o semnificatie speciala.1.4. . Rezulta de aici ca identificatorul calculatorului cu aceasta adresa de retea este 44.255.85.255.2. avand identificatorul reprezentat pe 3 octeti: 195. O astfel de adresare determina o difuzare limitata doar la aria retelei locale.85.44.4.65. fiind adresat tuturor calculatoarelor care fac parte din ea.85. Aceasta adresa IP desemneaza toate calculatoarele din reteaua locala.PROGRAMARE IN JAVA . de exemplu 10001101.85. Desi s-ar fi putut reprezenta adresa in hex 8D552C01 s-a optat pentru reprezentarea zecimala a valorii fiecarui octet.0 sau 195.4.255 sau 195. avand adresa IP 141. Daca ar fi reprezentat in zecimal ar fi dificil sa determinam pe baza valorii 2371169281 carei clase apartine reteaua locala.4. Astfel s-au definit adresele IP speciale: ¾ {netid 0} – de exemplu 141. Deoarece identificatorul unei retele din clasa B este reprezentat pe doi octeti. Adresele IP ale calculatoarelor din retelele mici din clasa C incep cu bitii 110 si in consecinta primul numar zecimal al adresei va fi cuprins intre 192(11000000) si 223(110111111). Astfel.1. si pornind de la aceasta sa determinam identificatorul retelei sau a calculatorului. Adresele IP ale calculatoarelor din retelele medii din clasa B incep cu bitii 10 si in consecinta primul numar zecimal al adresei va fi cuprins intre 128 (10000000) si 191(10111111).Note de curs 303 Curs 25 Reprezentarea zecimala a adreselor IP Am vazut ca o adresa IP este un numar intreg pe 4 octeti memorat de calculator in forma binara. acesta fiind rezervat pentru acest caz. Mesajul trimis la o astfel de adresa de IP nu va depasi ruterul-gateway al retelei fiind adresat implicit tuturor calculatoarele retelei locale.1 vom trage imediat concluzia ca reteaua careia ii apartine calculatorul cu aceasta adresa de IP este o retea de dimensiune medie din clasa B. Dupa primul numar al adresei deducem ca este vorba de o retea din clasa C.

224. Interogarea se face transmitand un mesaj multicast pe adresa 244. unde X este orice numar cuprins intre 0 si 255.0.5. Mesajul transmis pe aceasta adresa 0. Calculatorul care emite mesajul pe o astfel de adresa se adreseaza pe sine. Ruterele afla despre alaturarea sau parasirea unui grup de catre un calculator din reteaua subordonata prin interogarea periodica a tuturor calculatoarelor din aceasta subretea. La randul lor... Mecanismul de comunicare descris mai sus implementeaza protocolul Internet Group Management Protocol (IGMP).0 .255. ruterele comunica intre ele pentru a-si actualiza tabelele de rutare a mesajelor multicast transmise prin reteaua IP.0.1.255 . identificat de o adresa IP speciala avand primii biti 1110.0.128 ..X. Din aceste mesaje ruterul afla adresele grupurilor la care s-au alaturat calculatoarele din subretea.0.0. ruterele retelelor locale trebuie sa stie daca primind un mesaj adresat unui grup sa-l difuzeze sau nu in reteaua lor locala. La receptionarea mesajului.0.0.255 .1 intr-o retea locala din clasa B se adreseaza calculatorului cu numarul 44. In acest scop el tine o tabela interna cu evidenta grupurilor din reteaua locala subordonata.0.304 CURS 25 ¾ {0 0} – adica 0. ¾ {0 hostid} – de exemplu 0.0.6.44.44.2 grupul tuturor ruterelor din subretea Sunt nealocate adresele: .224.2.1 din aceasta retea.5. In acest caz calculatoarele care vor sa primeasca sau sa transmita mesaje “de la unul la toti ceilalti membri ai grupului” trebuie sa se alature unui grupretea din clasa D. De exemplu: .0. Unele adrese sunt alocate standard unor grupuri de conferinta sau altor scopuri.0.12 .0.0.0.0. Multicasting Pe langa modalitatea de difuzare a mesajelor catre toate calculatoarele unei retele locale descrisa mai sus (prin adresarea cu 255.27 .0.128 .0.255.3 .0.1 sau 0. Retele din clasa D.0.0.1 el il va recunoaste si accepta stiind ca ii este destinat.224. Adresa de baza 224. intorcandu-se la acesta fara a fi transmis pe canalul de comunicatie la nivel fizic (cablu).224.255 . Pachetul este pur si simplu copiat din bufferul de emisie in bufferul de receptie ale aceluiasi calculator.0.224.X. Daca calculatorul din reteaua 141. Adresa unui astfel de grup-retea din clasa D are in primul octet un numar cuprinse intre 224 (11100000) si 239(11101111). este destinat calculatorului emitent.224.1 grupul toturor calculatoarele din subretea . ¾ {127 orice} – Orice mesaj expediat pe adresa IP 127.0.0. Orice calculator din reteaua IP poate sa se alature unui grup.X. Petru actualizarea tabelei.44.0.233.1 primeste un mesaj cu adresa destinatarului 0.224. In consecinta.85.0.224.0 este rezervata. el va gasi in campul de adresa al expeditorului din datagrama propria adresa pe care nu o cunostea.224.255 sau {hostid –1}) mai exista o forma de difuzare catre un anumit grup variabil de calculatoare numita multicasting. actualizand tabela interna.224.1. .0. Toate calculatoarele din subretea care s-au alaturat unor grupuri raspund cu mesaje adresate ruterului.224.0.1 catrea toate calculatoarele din subretea.0.0.255 .44. O astfel de adresare este utila daca calculatorul vrea sa –si afle propria adresa de IP.0. ruterul trebuie sa afle daca in reteaua sa locala exista calculatoare care s-au alaturat unui grup.6.

O alta problema care poate sa apara la utilizarea protocolului UDP este absenta confirmarii de primire a mesajului. protocolul UDP nu se va sesiza de acest lucru deoarece nu prevede confirmarea de primire din partea destinatarului.1 – Structura pachetului UDP In aceasta etapa poate apare un fenomen deranjant. Daca dimensiunea datagramei depaseste dimensiunea maxima admisa de protocolul de la nivelul legaturii de date. Probabilitatea unei sosiri in ordine diferita a mesajelor la comunicatia intr-o retea locala este nula.1 si il paseaza nivelului IP. Dimensiunea blocului de date ce poate fi incapsulat intr-un pachet la nivelul legaturii de date este limitat de dimensiunea bufferelor de emisie/receptie ale interfetei de retea. protocolul UDP opereaza intr-un mod orientat pe transmiterea datagramelor. Protocolul UDP (User Datagram Protocol) satisface aceste cerinte. El nu incearca sa stabileasca o legatura intre aplicatii ci doar incapsuleaza datele intr-un pachet UDP avand structura din figura 25. Fig. datagrama este pierduta (prin oprirea unui ruter chiar in momentul in care datagrama se gasea la el). Spre deosebire de protocolul UDP nu garanteaza ajungerea la destinatie a mesajului. sa ajunga la destinatie intr-o ordine diferita. Desi ordinea de transmitere a datagramelor este cea corecta. Protocolul TCP retransmite mesajul de mai multe ori daca nu primeste dupa un timp fixat raspunsul de confirmare. respectiv sa extraga datele din pachetele UDP receptionate prin acest canal si sa le dirijeze spre porturile de destinatie specificate in antetul pachetului UDP primit. . Dupa un numar de retransmiteri renunta si avertizeaza aplicatia expeditor despre esecul stabilirii legaturii. misiunea sa limitandu-se doar la multiplexarea porturilor . Pentru aceste aplicatii este suficient un protocol la nivelul transport care sa asigure comunicatia intre aplicatii rulate pe calculatoare diferite intr-o retea IP si un mecanism minimal de validare a integritatii mesajelor receptionate. pachetul UDP este fragmentat si incapsulat in mai multe datagrame transmise succesiv. protocolul UDP nu mai face acest lucru. Protocolul UDP nu face acest lucru. La nivelul IP pachetul UDP este ambalat intr-o datagrama IP si transmis nivelului inferior pentru expeditie. Astfel daca pe traseu. pachetele nefiind rutate.Note de curs 305 Protocolul UDP Exista aplicatii care nu necesita robustetea (fiabilitatea) protocolului TCP. ele s-ar putea. Spre deosebire de protocolul TCP care asigura asamblarea secventelor mesajului in ordinea corecta. sa le incapsuleze in pachete UDP si sa plaseze aceste pachete in canalul de comunicatie comun IP. De exemplu dimensiunea maxima a blocului de date intr-un pachet Ethernet este de 1500 de octeti.PROGRAMARE IN JAVA . Spre deosebire de protocolul TCP bazat pe stabilirea unui canal virtual de comunicatie intre aplicatii. In aceste conditii aplicatiile care apeleaza la protocolul UDP pentru comunicatie trebuie sa asigure ele dezasamblarea/asamblarea mesajelor inainte/dupa transmisie/receptie. datorita rutarii.sa preia datele de la porturi. Acelasi lucru se va intampla daca calculatorul de la adresa de destinatie nu exista sau este oprit. Astfel blocul de date expediat ar putea ajunge la destinatie un pic “amestecat”.25.

Each entry should be kept on an individual line.94. The IP address and the host name should be separated by at least one space.65.<domeniu> cum ar fi de exemplu big_crash.255. De asemenea cele 1000 de calculatoare de destinatie pot fi grupate intr-o retea de tip D iar mesajul poate fi transmis o singura data.hacker. Costul in resurse ale sistemului pentru crearea si mentinerea conexiunilor pe perioada difuzarii mesajelor este mare. For example: 102. Un mecanism simplu de rezolutie a adresei IP pe baza unei adrese simbolice se bazeaza pe existenta unui fisier hosts in care sunt editate asocierile {adresa simbolica – adresa IP}. El este recomandat pentru aplicatii care lucreaza in cooperare. Din acest motiv s-a prevazut mecanismul de adresare a calculatoarelor dintr-o retea IP printr-un nume simbolic de forma <nume host>.1 195.acme. daca va folosi protocolulea va trebui sa stabileasca 1000 de conexiuni prin canale virtuale. comments (such as these) may be inserted on individual lines or following the machine name denoted by a '#' symbol. Este sarcina aplicatiei sa repete cererea daca nu a primit raspunsul intr-un timp dat sau sa renunte daca nu primeste raspuns la mai multe cereri succesive.com # source server # x client host 127.acme.255.ro . In pus. in regim de multicasting.0. Este bine ca atat cererea cat si raspunsul trebuie sa incapa intr-o singura datagrama. in loc de 195. pe principiu cerere-raspuns. The IP address should be placed in the first column followed by the corresponding host name.306 CURS 25 Aceste caracteristici fac ca protocolul UDP sa fie mai simplu si mai eficient decat protocolul TCP cu singurul dezavantaj ca este mai putin sigur. aplicatia va trebui sa inchida aceste 100 de conexiuni. cate una pe fiecare rand ca in exemplul de mai jos: # # # # # # # # # # # # # # # # # # # # Copyright (c) 1998 Microsoft Corp.com x. Adrese simbolice si serviciul DNS Folosirea adreselor IP este greoaie deoarece acestea sunt greu de memorat. Folosind protocolul UDP aplicatia poate expedia cele 1000 de mesaje cu costuri mult mai mici si intr-un timp mult mai scurt.97 38.0.1.255 cerand distribuirea acesteia in regim de broadcasting in reteaua locala sau de forma {netid 1} pentru difuzarea catre toate calculatoarele din reteaua netid. Dupa terminarea difuzarii mesajului prin transmiterea lui pe fiecare conexiune in parte.ro. This is a sample HOSTS file used by Microsoft TCP/IP stack for Windows98 This file contains the mappings of IP addresses to host names.54. o aplicatie poate plasa o singura datagrama cu adresa de IP de forma 255.4.63.25. De exemplu daca o aplicatie are de trimis acelasi mesaj la 1000 de aplicatii ruland pe alte calculatoare.hacker. Additionally.10 rhino. De asemenea protocolul UDP este util in cazul aplicatiilor care difuzeaza un mesaj in retea simultan la mai multe calculatoare. pe adresa de IP a grupului.4.65.1 localhost big_crash.

In fisierul hosts al serverului de nume x se vor inregistra numele si adresele de IP ale calculatoarelor din domeniul root deservit. Acest mecanism este insa ineficient deoarece nu este practic posibil sa tii evidenta tuturor calculatoarelor din reteaua IP al caror numar se poate ridica la zeci de milioane. Astfel la configurarea modulului TCP/IP a tuturor calculatoarelor din reteaua IP cu exceptia lui x DNS calculatorul cu adresa IP 195. La acest port asculta aplicatia server care ruleaza pe DNS. y si z si celalalte trei calculatoare ale retelei 196. Pe calculatoarele functionand sub sistemul de operare Unix..4 i se adauga un nou calculator w. Cea mai raspandita astfel de aplicatie este Barkley Internet Domain Name (BIND) server.4.root in fisierul hosts propriu. pe nivelul UDP la portul 53.4.4 si 196. r. Calculatorul pe care se executa o astfel de aplicatie se numeste server de nume – Domain Name Server sau mai scurt DNS. se va dezactiva DNS-ul.65.23.1 In cazul serverului de nume x. aplicatia BIND este numita named. Daca expeditorul este un alt calculator din retea. acesta nu va putea fi adresat prin adresa simbolica pana nu este inregistrat in fisierul hosts a calculatorului DNS x.root. Sa presupunem ca unul din calculatoarele din retea trimite un mesaj pe adresa r.3 asociata numelui r.65.1 Acasta adresa IP a serverului de nume DNS. Toate calculatoarele din reteaua IP sunt impartite pe domenii.root si o va trimite ca raspuns modulului IP al solicitantului. Daca subretelei 195. Domeniul net este gestionat de exemplu de calculatorul x avand adresa IP 195.PROGRAMARE IN JAVA .root in fisierul hosts al calculatorului propriu.Note de curs 307 In momentul in care o aplicatie solicita transmiterea unei datagrame la adresa simbolica big_crash. si nu gaseste inregistrarea lui r. r..75.23. el va gasi in acest fisier inregistrarea : .65. Primind cererea ea va cauta adresa IP a lui r... va incapsula mesajul in datagrama si o va trimite pe aceasta adresa de IP.75) de cate trei calculatoare. fiecare domeniu fiind gestionat de un calculator pe care ruleaza o aplicatie server ce gestioneaza numele calculatoarelor din domeniul sau.23. big_crash.root. Un astfel de fisier ar trebui actualizat pe fiecare calculator din reteaua IP ori de cate ori apare un nou calculator in retea sau un calculator existent doreste sa-si schimbe numele. In domeniul root sunt inscrise cele trei calculatoare ale retelei 195.De exemplu reteaua IP formata din 6 calculatoare organizate in doua subretele locale (195. Modulul sau IP va cauta in fisierul hosts al calculatorului propriu pentru a gasi adresa IP a lui r. Daca expeditorul este calculatorul x care joaca rolul de DNS in reteaua IP. Prima componenta desemneaza numele atribuit calculatorului gazda (host) – in exemplul nostru. Din acest motiv s-a gasit un mecanism mai eficient de rezolutie.root. Cea de a doua componenta desemneaza domeniul careia ii apartine calculatorul big_crash(hacjker.75 avand numele p.23. Gestiunea unui numar prea mare de calculatoare este dificila iar la un numar foarte .ro modulul care implementeaza protocolul IP deschide fisierul hosts si cauta in el adresa IP asociata numelui simbolic respectiv. este inregistrata de softwareul TCP/IP la configurare.4 sub numele x.. Reteaua IP are un singur domeniu: root.root .ro).4. Va extrage adresa IP 196.. Pentru ca acest mecanism sa functioneze adresa simbolica are doua componente – nume_host si domeniu.75. Va extrage adresa IP 196.root .hacker.65.65. unde va gasi randul: ..3 asociata numelui r.1. modulul sau IP va transmite o cerere DNS-ului adresata la adresa IP 195. q si r.65. Acesta va incapsula mesajul in datagrama si o va trimite pe aceasta adresa de IP..

Acesta observand ca subdomeniul careia ii apartine adresa simbolica este netB o va redirecta catre DNS-ul subordonat p care gestioneaza acest subdomeniu. Acesta la randul sau va constata ca domeniul adresei simbolice este in jurisdictia lui.23.4 trimite un mesaj pe adresa r. Acesta stiind ca gestioneaza subdomeniul netA o va pasa spre rezolvare DNS-ului sau ierarhic superior adica lui x.root. In fisierul hosts a lui y vom inregistra pe w.root.2 este prezentat acest mecanism de servire a cererilor rezolvare a adreselor simbolice. fiecare gestionat de un DNS propriu.23. In figura 25. Negasind-o va emite o cerere catre DNS-ul sau adica catre y.4 iar p DNS-ul retelei 196. In exemplul nostru vom imparti domeniul root in doua subdomenii netA si netB.23. o va gasi inregistrata in fisierul sau hosts si va extrage de acolo adresa de IP asociata 196. Calculatorul y va fi desemnat DNS-ul retelei 195.75. Fig. La configurarea modulelor IP ale calculatoarelor y si p se va inregistra ca DNS adresa lui x. .4 iar in subdomeniul netB vom incadra calculatoarele q si r ale retelei 196. La configurarea modulelor IP ale calculatoarelor w si z se va inregistra ca DNS adresa lui y iar a lui pe q si r adresa lui p. Sa presupunem ca unul din calculatoarele din reteaua 195. In subdomeniul netA vom incadra calculatoarele w si z ale retelei 195. y si z iar in fisierul hosts a lui p vom inregistra pe p.65.2 – Servirea de catre DNS a cererilor de rezolvare a adreselor simbolice Se observa ca gasirea de catre DNS a adreselor IP asociate adreselor simbolice se bazeaza pe organizarea ierarhica a domeniilor.netB.308 CURS 25 mare imposibila.75.netB. Specificarea in cadrul adresei simbolice a numelui radacinii nu este obligatorie cautarea facandu-se implicit si acolo. q si r.65. Aceasta adresa IP o va returna lui x care la randul sau o va returna lui y care la randul sau o va expedia ca raspuns solicitantului. Solutia consta in impartirea domeniului in subdomenii. Modulul sau IP va cauta in fisierul hosts al calculatorului propriu pentru a gasi adresa IP a lui r. subordonat DNS-ului domeniului root.65.3.25.75.

DLL in cazul versiunilor Windows pe 16 bit si WSOCK32. Similar. Unul din aceste module asigura servicii de comunicatie in retea TCP/IP. uk pentru Anglia. Ca standard pentru serviciile oferite de acest modul a fost adoptat cel prevazut in S. int – organizatii internationale.netB. Windows ofera astfel servicii de comunicatie in retea TCP/IP printr-un modul .netB. BSD Unix. nu mai este nevoie sa fie specificat subdomeniul netA. mil – armata SUA iar gov – institutii guvernamentale ale SUA.ro. pentru a adresa calculatorul w de pe un calculator din acelasi domeniu.PROGRAMARE IN JAVA .ro. clienti. va aparea astfel un nou subdomeniu x. etc.25. fr pentru Franta.root este suficient sa se specifice doar subdomeniul p. In caz contrar DNSul domeniului lui z va considera ca este cautat un calculator cu numele r aflat in domeniul sau (r. edu de institutii de invatamant. Avantajul unei astfel de organizari este ca fiecare subdomeniu poate sa-si creeze la randul sau in mod independent propriile subdomenii fara ale anunta in vre-un fel nivelului ierarhic superior. de pentru germania.DLL pentru versiunile pe 32 de bit). intreprinderea va putea sa-si defineasca singura subdomenii ca servicii. cn pentru china. us pentru SUA. Adresarea se poate face numai prin numele w. S. cotabilitate. Fig. Subdomeniul trebuie specificat numai daca calculatorul adresat se gaseste in alt subdomeniu. net de furnizorii de servicii Internet.O. apartinand unei intreprinderi X poate fi inregistrata ca subdomeniu x al domeniului ro prin simpla inregistrare a serverului de nume a acestei retele in serverul de nume al domeniului ro. Astfel aparitia retele noi X in Romania.x. de exemplu pentru a adresa calculatorul r din z este necesar sa specificam atat numele calculatorului cat si subdomeniul: r.netB. se pentru suedia. ja pentru japonia. Aplicatia dialogheaza cu modulul WinSock API apeland procedurile oferite de acesta iar . In Internet exista definita o ierarhie de subdomenii deservite de servere de nume ca cea reprezentata in figura 25.netA) pe care evident ca nu-l vagasi in fisierul sau hosts si va da un mesaj de eroare.3.O.x. De asemenea sunt definite domeniile regionale cum ar fi ro pentru Romania. inregistrandu-le doar pe serverul de nume al domeniului x.ro. ca pentru Canada.Note de curs 309 De exemplu in loc sa se specifice adresa simbolica completa completa p.3 – Ierarhizarea domeniilor in Internet Domeniul com este folosit de organizatii comerciale.x. Socluri (Sockets) In cadrul nucleului unui sistem de operare este contine de module API – Application Programming Interface care ofera accesul programatorului la o serie de servicii ale sistemului de operare.biblioteca cu legare dinamica DLL (Dinamic Link Library) cunoscut sub numele WinSock API (fisierul WINSOCK. Aplicatiile acceseaza serviciile de retea oferite de sistem (trimitere si primire de date intr-o retea TCP/IP) prin intermediul interfetei oferite de WinSock API.ro. Apoi. in pentru India.ro etc.

Acesta este asemanator unui specificator (handler) de fisier fiind un numar intreg pozitiv care identifica unul din cele doua puncte terminale al unui canal de comunicatie virtuale. aceasta receptioneaza cererea si poate sa o accepte deschizand un canal de comunicatie duplex pe portul n. atunci socketul (capatul dinspre client al canalului de comunicatie stabilit cu serverul) ar puatea fi descris prin combinarea adresei IP cu numarul portului: 195. aplicatia client poate sa-i transmita serverului mesaje-cereri de servicii. Pentru a obtine un serviciu de la o aplicatie server. Mai curand este un specificator de acces la date care include atat adresa de IP cat si portul prin care se realizeaza comunicatia. Dupa ce este recunoscut de operator. pot fi sub forma de stream bidirectional sau de datagrama. Aplicatia server ofera servicii aplicatiilor client. Odata creat acest acest canal. asteptand noi telefoane de la alti reprezentanti comerciali. Elementul central in crearea si gestionarea unui canal virtual de comunicatie intre doua aplicatii este soclul (socket). In momentul in care apare o cerere de conectare din partea unei aplicatii pe portul n al calculatorului pe care ruleaza aplicatia server. iar numarul de telefon este portul TCP. Pentru aceasta el trebuie sa ia legatura telefonica cu firma pe care o reprezinta. Aceasta simplifica in mare masura programarea aplicatiilor de retea punand la dispozitia programatorului proceduri de comunicatie mai puternice si mai usor de folosit. Pentru transmisia datagramelor WinSock API va apela la UDP iar pentru date de forma unui stream la TCP. Ca sa clarificam lucrurile sa urmarim urmatorul scenariu.4. acesta ii face legatura telefonica cu functionarul de la serviciul desfacere care ii poate furniza datele solicitate de mine. ¾ Reprezentantul comercial este soclul client. Datele transmise pe acest canal sunt bufferizate atat de aplicatia server care transmite datele cat si de aplicatia client care le receptioneaza. La firma de comercializare a echipamentelor de calcul condusa de mine exista un reprezentant permanent al unei firme producatoare de echipamente de calcul. aplicatia client trebuie sa se conecteze la aplicatia server. Eu ii solicit sa imi prezinte o specificatie de preturi si caracteristici tehnice ale unor sisteme in configuratia dorita de mine aceasta fiindu-mi necesara pentru intocmirea unei oferte.1 comunica cu o aplicatie server primind date de la acesta prin portul 3000. Eu ii indic unul din telefoanele aflate pe biroul meu. Datele transmise pe canalul virtual al carui capat dinspre client este soclul. Aplicatia server asteapta cereri de conectare de la aplicatiile client “ascultand” un port TCP prestabilit n. Operatia de legatare (bind) a soclului la port s-a facut in momentul in care i- .1.310 CURS 25 WinSock API la randul sau stie sa dialogheaze cu implementarea interna a protocolului TCP/IP preluand asupra sa operatiile de rutina necesare crearii si gestionarii unor canale de comunicatie virtuale. intre cele doua stabilindu-se un canal virtual de comunicatie.65. Aplicatiile de retea comunica dupa schema client – server. dupa ce este pus in tema de reprezentantul firmei. caracterizand canalul de comunicatie virtula. De exemplu daca o aplicatie client aflata pe calculatorul 195. functionarul de la desfacere ii transmite acestuia prin faxul telefonului documentatia solicitata dupa care inchide telefonul. Soclul nu este tot una cu portul TCP.4.65. Acesta telefoneaza la un numar de telefon unde raspunde in permanenta un operator a carui sarcina este sa raspunda la solicitarile reprezentantilor comerciali ai firmei. La terminarea servirii serverul sau clientul pot inchide canalul de comunicatie virtuel. ¾ In acest exemplu biroul meu este calculatorul pe care ruleaza aplicatia client. Serverul raspunde aplictiei client rezultatul procesarilor solicitate prin mesajele-cerere. In acest timp.3000. Reprezentantul firmei imi inmaneaza datele solicitate. Dupa aceasta operatorul inchide.

Soclul server revine la asteptarea unei alte conectari . ¾ Eu sunt apelatia client care pentru a solicita un serviciu de la aplicatia server. Operatiile de mai sus si starile soclului sunt reprezentate in graful din figura 25. soclul server este disponibil asteptand noi cereri de conectare. ¾ Datele primite sunt faxul receptionat de la soclul functionar.creaza un soclu .transmite/primeste date prin soclu .4.dupa conectarea clientului. apeleaza la soclu.4 Operatiile de conectare prin socluri ale aplicatiilor client-server Functiile reprezentate in acest graf sunt proceduri ale WinSock API care pot fi apelate de catre aplicatiile client-server pentru realizarea comunicatiei intr-o retea IP. ¾ Operatorul este un “soclu server” care accepta apelul pe acest numar si creaza un alt soclu – functionarul de la desfacere.legarea sa la un anumit port TCP si adresa IP a calculatorului client .se conecteaza la server . Fig.astepta un apel de la client .25.creaza un soclu – server .Soclul nou creat executa operatiile de primire/trimitere a datelor cu clientul dupa care se inchide. In acest timp. Actiunile de creere a unui canal de comunicatie virtual pot fi grupate in doua categorii: 1 Actiuni executate de aplicatia client: .leaga soclul la adresa IP si portul sau . serverul accepta conectarea creind un nou soclu pentru servirea clientului .inchide soclul-conexiune 2 Actiuni executate de aplicatia server: .Note de curs 311 am indicat reprezentantului un anumit telefon particular de pe biroul meu. Portul lui este numarul special de telefon de serviciu pe care numai el il poate folosi pentru a-l contacta pe operator.PROGRAMARE IN JAVA . .

¾ byte[] getAddress() – intoarce un tablou continand cei patru octeti ai adresei IP.out.44. System. InetAddress address – un obiect din clasa InetAddress care contine adresa IP pe 32 de bit a calculatorului gazda al aplicatiei de la celalalt capat al canalului de comunicatie.312 CURS 25 Clasele Java pentru aplicatiile de retea TCP/IP Limbajul Java ofera in pachetul java.85.getByName("nexus.Y. class GetIP { public static void main (String[] args) throws UnknownHostException { System. InetAddress localAddr– un obiect din clasa InetAddress care contine adresa IP pe 32 de bit a calculatorului gazda local ( pe care ruleaza aplicatia curenta). IOException ¾ public Socket(String host.portul TCP al aplicatiei de la celalalt capat al canalului de comunicatie. IOException Parametrii constructorilor au urmatoarea semnificatie: String host – un string continand adresa simbolica sub forma nume.ro"). int port.println( InetAddress.portul TCP al aplicatiei curente. } } Programul va afisa rezultatele din figura 25.println( InetAddress. int local Port. ¾ String toString() – intoarce un string continand numele si adresa de IP.net o serie de clase necesare realizarii aplicatiilor de retea bazate pe socluri.out.getByName("141. ¾ static synchronized InetAddress getByName(String hostName)throws UnknownHostException – intoarce un obiect InetAddress continand adresa calculatorului specificat prin adresa simbolica.toString()). int port .toString()).out. Ceilalti doi constructori permit construirea soclului specificand in plus si adresa si numarul de port de pe masina locala. int local Port) throws UnknownHostException. InetAddress localAddr. Primii doi constructori sunt folositi pentru a crea un soclu specificand doar adresa si portul aplicatiei cu care se doreste stabilirea legaturii.Z a calculatorului la care aplicatia doreste sa se conecteze. Adresa poate fi specificata fie sub forma simbolica nume.domeniu fie printr-un obiect al clasei InetAddress care contine adresa IP a calculatorului. int port) throws UnknownHostException.println( InetAddress. IOException ¾ public Socket(InetAddress address. int local Port) throws UnknownHostException. Una din acestea este clasa Socket.5.X. IOException ¾ public Socket(InetAddress address. InetAddress localAddr. Programul urmator demonstreaza utilizarea unora din aceste metode: import java.*. Acesti constructori sunt utili in cazul in care calculatorul local are mai multe adrese IP.domeniu sau IP sub forma W.toString()). int port) throws UnknownHostException.net.home. . int port. System. Ea are constructorii: ¾ public Socket(String host.getLocalHost(). Clasa final InetAddress ofera un mecanism unitar de manipulare a adreselor si defineste cateva metode utile pentru obtinerea adresei IP apeland la serviciul DNS: ¾ static InetAddress getLocalHost() throws UnknownHostException – intoarce un obiect dinclasa InetAddress reprezentand calculatorul local ¾ boolean equals(Object otherObject) intoarce true daca celalalt obiect este o instanta InetAddress continand aceeasi adresa.10").

codurile si mesajele de raspuns sunt definite de protocolul SMTP (Simple Mail Transfer Protocol). Regulile de dialog.25.7 – Comunicatia intre o aplicatie client si o aplicatie server SMTP . Clasa Socket defineste metode care permit scrierea/citirea in/din canalul virtual de comunicatie asociat.ro . setul de comenzi.PROGRAMARE IN JAVA . Metodele getInputStream() si getOutputStream() intorc referintele la aceste streamuri.7 si se desfasoara prin transmiterea de catre aplicatia client a unor comenzi aplicatiei server si receptionarea unor raspunsuri de confirmare de la aceasta.25. Dialogul intre aplicatia noastra client si aplicatia server este reprezentat in figura 25.Note de curs 313 Fig.5 – Obtinerea adresei unui calculator La creerea unui obiect din clasa Socket se deschide un canal virtual de comunicatie duplex intre aplicatia client de pe calculatorul local si aplicatia server de pe calculatorul corespondent. Programul din exemplul urmator se conecteaza la o aplicatie server de e-mail pe portul TCP dedicat 25 si ii transmite un mesaj pe adresa user@nexus.home. Fig. La terminarea comunicatiei cu aplicatia client trebuiesc inchise streamurile de I/O si apoi soclul apeland metoda close(). Canalul virtual de comunicatie este constituit din doua streamuri – unul de intrare si altul de iesire.

1 beta produs de Alt-N Technology.out. smtp.25.*.\r\n. DataOutputStream out=new DataOutputStream( smtp. out.getOutputStream()).ro\r\n". DataInputStream in=new DataInputStream( smtp.home.close().i++){ System.net.\r\n".io.writeBytes(command[i]).ro\r\n". }catch(Exception e){ System. for(int i=0.import java.} } } In figura 25.toString()).314 CURS 25 import java. in.25).i<command.print(in.flush().readLine()+'\n'). Fig.err.length. "message text\nmessage text\nmesagetext etc.println(e.8 – Protocolul de comunicatie client-server SMTP . "QUIT\r\n"}.print(in.out.close(). out.readLine()+'\n'+command[i]+'\n'). "RCPT To: teral@nexus. try{ Socket smtp=new Socket("nexus".*.getInputStream()).out. } System.close().8 sunt prezentate rezultatele afisate de aplicatie la consola si fereastra aplicatiei server MDaemon server 1. class SMTP{ public static void main(String[] args){ String command[]={"HELO smtp\r\n"."DATA\r\n". "MAIL FROM: teral@k.

Chiar daca este deja conectat printrun canal virtual cu o aplicatie client. serverul trebuie sa detecteze cererea de conectare si sa creeze un al doilea canal virtual de comunicatie cu cel de al doilea client care a solicitat conectarea la serviciile sale.1.Note de curs 315 Curs 26 Aplicatii server O aplicatie server trebuie sa poata accepta cereri de servire de la mai multi clienti simultan. Pentru aceasta ea trebuie sa stabileasca cate un canal virtual de comunicatie TCP ori de cate ori un client solicita conectarea. De exemplu am vazut in cursul anterior ca serverul de e-mail (SMTP) accepta conexiuni pe portul 25. el va crea un al doilea soclu cu un numar arbitrar x1 al portului si va stabili legatura cu clientul pe acest soclu. Asa cum am vazut. In momentul in care un client Y solicita prin portul sau y conectarea pe portul x al serverului. porturile de la capetele sale devin indisponibile pentru crearea unui alt canal. acesta receptioneaza cererea si poate accepta stabilirea legaturii. Stim ca un canal virtual de comunicatie are doua capete si are la fiecare capat cate un port. Aplicatia server X creaza un soclu pe portul cu numar fixat x (de exemplu 25 . Aplicatiile client care au de expediat mesaje e-mail solicita conectarea la server fara sa stie daca acesta este deja in legatura cu o alta aplicatie client sau nu. Fig.4 explicand functionarea lui. o aplicatie server care ofera o anumita categorie de servicii este contactata de aplicatia client pe un numar de port unic convenit dinainte. Se pune intrebarea care este mecanismul prin care mai multe aplicatii client se pot conecta la acelasi port cu un numar fixat al aplicatiei server? Acest mecanism a fost deja prezentat cand am prezentat in cursul trecut modulul WinSock API graful din figura 25. soclul cu numarul de port x ramane .W.cunoscut de toate aplicatiile client SMTP) si "asculta" la acest port asteptand cereri de conectare. etc. In acest fel.1 Servirea cererilor de conectare de catre o aplicatie server Avem o aplicatie server X si mai multe aplicatii client Y.26.Z. In acest caz. Odata creat un astfel de canal.PROGRAMARE IN JAVA . Sa analizam exemplul din figura 26.

Terminalul telnet trimite catre server liniile de caractere tastate de utilizator (afisate in ecou si in fereastra aplicatiei) si afiseaza liniile de text primite de la aplicatia server. Odata creat acest soclu. Soclul admite o coada cu maximum count clienti. Serverul revine din executia acestei metode numai atunci cand primeste o cerere de conectare din partea unui client pe portul soclului "ascultat". ¾ public ServerSocket(int port. apeland metoda accept() serverul este blocat.1 mai sunt redate si mesajele afisate de aplicatia server la consola si cele afisate in fereastra telnet.O. In momentul in care primeste o cerere de conectare. Dupa receptionarea parolei. Pentru a testa aplicatia server ne vom folosi de aplicatia de sistem telnet. Daca un alt client Z va cere prin portul sau z conectarea la portul x al serverului. (de exemplu de WinSockAPI) si returneaza soclul (obiect din clasa Socket) de la capatul dinspre server al canalului. Soclul admite o coada cu maximum 50 de clienti. Clientii ale caror cereri de conectare sosesc in timp ce serverul este ocupat cu servirea unui client se aseaza intr-o coada de asteptare. w-x5. Daca parola receptionata nu este corecta reia inca de doua ori citirea parolei dupa care inchide conexiunea. Cand serverul termina servirea clientului curent si executa din nou metoda accept() va prelua cererea primul client din coada si va crea un canal virtual de comunicatie cu acesta. Daca cele doua stringuri sunt egale afiseaza mesaj de bun venit "Bine ai venit Alibaba! Exprima-ti o dorinta (QUIT. ¾ public ServerSocket(int port. Soclul admite o coada cu maximum count clienti.. InetAddress localAddr) throws IOException – Acest constructor se foloseste in cazul aplicatiilor server care ruleaza pe un calculator cu mai multe interfete de retea fiecare cu o adresa IP proprie.W. o compara cu stringul "sesam deschidete". In caz contrar va relua receptionarea unei comenzi.CLOSE):" asteptand apoi receptia unui sir de caractere din cele trei. Ea permite programatorului sa faca asocieze un soclu de "ascultare" cu un port. int count) throws IOException . Canalul virtual de comunicatie stabilit intre clientul Y si serverul X are deci la capatul clientului portul cu numarul y iar la capatul dinspre server portul x1. Aceasta emuleaza un terminal VT100 si permite crearea unei conexiuni la un server a carui adresa si port se configureaza (figura 26..316 CURS 26 liber si serverul se poate intoarce la "ascultarea" lui pentru stabilirea altor legaturi cu alti clienti. serverul solicita aplicatiei client o parola. Odata revenit din metoda accept() serverul poate sa dialogheze cu clientul prin intermediul soclului returnat de metoda. In figura 26. In momentul in care conexiunea este stabilita. Daca sirul receptionat este unul din cele trei va afisa mesajul "Ascult si ma supun stapane!" dupa care daca comanda este "QUIT" sau "EXIT" inchide conexiunea iar daca este "CLOSE" inchide in plus si soclul server si se termina. . In programul urmator este prezentata o aplicatie server care accepta conexiuni pe portul 2222.V. v-x4. El creaza un soclu server care asculta la portul specificat pe adresa IP locala a uneia din interfete.1). acesta va stabili legatura pe un port cu numar arbitrar x2 diferit de x1 alocat anterior. alocand la fiecare solicitare un nou port xk si creind canale virtuale de comunicatie cu fiecare client in parte u-x3. intrand intr-o stare de asteptare a unei cereri de conectare din partea unui client. Soclul pe care "asculta" serverul este implementat in Java printr-o clasa speciala ServerSocket. Clasa ServerSocket are trei constructori: ¾ public ServerSocket(int port) throws IOException – creaza un soclu server care asculta la portul specificat. Serverul va continua sa accepte conexiuni la cerere pentru clientii U..(vezi figura 26. int count.2).creaza un soclu server care asculta la portul specificat. metoda accept() creeaza un canal virtual de comunicatie cu clientul care a solicitat conectarea pe un port disponibil alocat de S. etc. EXIT.

*.class import java.. disconect:{ int k=0. in=new DataInputStream(s.net.cmd.out. do{ out. ServerSocket ss=new ServerSocket(2222). out=new PrintStream(s. if(psw.readLine(). out.print("password:"). for(.Note de curs 317 Figura 26.println("Alibaba access granted.println("Waiting for connection request. psw=in.").accept(). PrintStream out.out.PROGRAMARE IN JAVA .").").){ .. import java.print("Bine ai venit Alibaba!"+ " Vre-o dorinta (QUIT/EXIT/CLOSE)?").. Socket s.io. DataInputStream in.getInputStream())..equals("sesam deschide-te")){ System.*. System.out.. close:{ for(.println("New connection.getOutputStream())..){ System.1 – O sesiune telnet de conectare la serverul Gate.. class Gate{ public static void main(String[] args){ try{ String psw. s=ss..

.. } } in. } catch(Exception e){ System.println(e. break disconect.println("Connection closed.close(). System. } } out.close().318 CURS 26 cmd=in.. } out. Solutia evidenta este ca activitatea sa fie distribuita intre mai multe threduri cu sarcini specifice. Similar daca asteapta receptia unui mesaj dintr-un stream de intrare.readLine().. }while(k<3)..out.println("Ascult si ma supun stapine!\r"). Sunt situatii in care o atare comportare a serverului este inacceptabila.close().println(cmd).println("Connection closed.close().equals("EXIT")){ out.println("Server shut down.close().close().} } } Aplicatii client-server multithread In exemplul anterior serverul actioneaza de asa maniera incat nu apeleaza functia accept() decat atunci cand clientul servit curent inchide sesiunea de lucru.print(cmd+"!!!!!(QUIT/EXIT/CLOSE)?").equals("QUIT")||cmd. System. iarasi este blocat in executia metodei readLine() pana o aplicatie client nu transmite un mesaj. s.. Acesta va depune mesajul intr-un buffer gestionat de un alt . Ori de cate ori se creaza o noua conexiune ea va fi inmanata spre gestionare unui thread care va receptiona mesajele sosite de la clientul conectat la celalalt capat al acestui canal virtual de comunicatie. Sa analizam de exemplu cazul urmator: Mai multe aplicatii client trebuie sa converseze intre ei prin schimb de mesaje..println("Connection closed. k++.out. s. ss. if(cmd.close().."). receptionarea mesajelor si retrimiterea mesajelor sosite catre ceilalti clienti conectati.out.equals("CLOSE")) break close.").out. System. System.err. Sarcina aplicatiei server este sa asigure evidenta clientilor care sunt conecti la un moment dat si transmiterea unui mesaj sosit de la un client la toti ceilalti.. In acest timp nu poate primi cereri de conectare de la alti clienti. In acest timp ceilalti clienti care au solicitat intre timp conectarea sunt tinuti in coada de asteptare a soclului server. Thredul principal ar putea sa se ocupe cu primirea cererilor de conectare si gestiunea conexiunilor.. Este evident ca numai threadul principal nu poate face fata acestei sarcini deoarece de exemplu daca asteapta conectarea unui client el este de fapt blocat in executie metodei accept() si deci nu poate sa primeasca mesaje de la ceilalti clienti deja conectati."). out.toString()).\r"). out. out. in. } if(cmd. Nici unul nu stie cati clienti sunt conectati la un moment dat si cine sunt ei.println("Wrong password. In acest caz serverul trebuie sa asigure deci simultan servirea cererilor de conectare.\r").

Note de curs 319 thread care se ocupa cu expedierea mesajelor din buffer spre toti ceilalti clienti conectati. si-l va "implanta" in primul "slot" i liber al tabloului de conexiuni. Tx si Rx. . s.3 este reprezentata schematic cooperarea dintre threadurile aplicatiilor client si server pentru realizarea acestei scheme de comunicatie. el nu va putea sa execute in acelasi timp metoda de citire a mesajului introdus de utilizator de la tastatura.3 – Cooperarea threadurilor in aplicatiilor client si server Aplicatia server.PROGRAMARE IN JAVA . Fig. threadul s va reincepe "ascultarea" portului 2222 asteptand o noua cerere de conectare. Pe de alta parte si clientii trebuie sa fie multithread deoarece un singur thread nu poate gestiona singur si trimiterea si receptia mesajelor.26. Daca de exemplu el se afla blocat in executia metodei readLine() asteptand sosirea unui mesaj in bufferul streamului de intrare. Dupa aceste operatii. dupa cum se vede din schema. In figura 26. In momentul in care primeste o cerere de conectare el va crea un "canal" de comunicatie duplex prin soclul intors de metoda accept() a soclului server x. este bazata pe activitatea a trei clase de threaduri. De aceea si aplicatia client trebuie sa aibe doua threaduri – unul care sa se ocupe cu receptia mesajelor sosite de la server si altul care sa citeasca o linie de text de la tastatura si sa o expedieze sub forma de mesaj serverului pentru difuzare. La creerea canalului de comunicatie duplex se va crea si un thred din clasa Rx care va incepe receptia mesajelor sosite prin soclul canalului din slotul i. Threadul s este cel care gestioneaza cererile de conectare. El "asculta" la soclul server x pe portul cu numarul 2222 (ales arbitrar).

. Referinta la elementul adaugat se inscrie si in variabila tail. Metodele push() si pop() sunt sincronizate. devenind astfel ultimul element din lista.26. La extragerea elementelor din lista se apeleaza metoda push() care "dezleaga" primul element al listei inscriind in variabila head referinta continuta de campul de legatura al primului elementului din lista (referit de head). primul iesit) ale carei elemente sunt generate dinamic. aceasta "legatura" este null. In momentul receptiei acestuia. Daca lista nu este vida. Coada de pachete este o lista inlantuita de tip FiFo (First In First Out – primul intrat.320 CURS 26 Threadul Rx asteapta sosirea unui pachet continand un mesaj de la client. lista fiind accesata de mai multe threaduri executate concurent (Threadurile Rx inscriu pachete in lista iar Tx extrage pachete din lista). Variabila head refera primul element al listei iar tail pe ultimul. daca lista este vida threadul Tx este blocat la apelul metodei pop() pina la adaugarea de catre un thread Rx a unui pachet nou in lista. In plus. El extrage pachetele din coada si le expediaza pe toate canalele virtuale de comunicatie gasite in sloturile tabloului de conexiuni. referinte la obiecte de tip element al listei. La adaugarea elementelor noi in coada se executa metoda pop(obj) care daca lista este vida inscrie referinta obj in ambele variabile head si tail. Daca clientul se deconecteaza inchizand soclul de la capatul sau al canalului de comunicatie threadul Rx receptioneaza un string null. Threadul Tx are sarcina sa reexpedieze pachetele din coada de pachete. Fig. unul continand informatia utila iar celalalt o "legatura"referinta la urmatorul element din lista.4 – Operatii de adaugare/extragere de elemente in/din coada Coada are doua variabile head (cap) si tail (coada). Initial coada este vida si deci cele doua elemente contin valorile null. ultimul element din lista se leaga la elementul nou adaugat prin inscrierea in campul sau de legatura a referintei la acesta. Daca elementul este ultimul element din lista. Ea are structura din figura 26.4. Dupa aceasta operatie threadul Rx se "sinucide" eliberand memoria alocata. Elementele listei sunt obiecte care au doua campuri. Threadul inchide la randul sau canalul si il extrage din tabloul de conexiuni. lista devenind din nou vida. Metoda pop() intoarce referinta la obiectul extras din coada. il inscrie intr-o coada de pachete pentru reexpediere dupa care revine la receptionarea unui nou pachet. Daca elementul extras este ultimul ( are in campul de legatura referinta null) se inscrie null si in variabila tail.

import java. private Socket s.println("Server socket error: "+ ex.server. private Queue que. for(i=0.ch[i].out.toString()).println("Error closing socket: "+ ex. server.start().ch[i]=new Channel( server.tx. System.toString()). TCPServer server=new TCPServer(). Ea creaza si intoarce referinta la un tablou de octeti construit pe baza argumentului String msg adaugandu-i la sfarsit caracterele de control <CR><LF> care constituie terminatorul de linie.Note de curs 321 Pachetele sunt blocuri de octeti de dimensiune variabila construite de metoda statica newPacket(String msg) a clasei Packet.tx. private final static int MAX_CLIENTS=50.close().server.que).println("New connection on channel "+i).ss.out. System.i<MAX_CLIENTS.s. } catch(IOException ex){ System. for(."). server.tx=new Thread(server).toString())..accept(). try{ ss=new ServerSocket(PORT). } que=new Queue().out. } } } } .ch[i]==null)break.io.s=server. public TCPServer(){ ch=new Channel[MAX_CLIENTS]..setDaemon(true).err.i++) if(server.s..println("server is listening on port nr. private Thread tx.i.exit(0). } catch(IOException ex){ System. private ServerSocket ss.){ try{ server.println(ex. class TCPServer implements Runnable{ private final static int PORT=2222. } System. server.ch.println("Connection request. if(i<MAX_CLIENTS){ System.net.PROGRAMARE IN JAVA ."+PORT).*.start().out. Programul este prezentat mai jos: import java. }else{ try{ server.out. } public static void main(String[] args){ int i.*. private Channel[] ch. server. } catch(IOException ex){ System. server.

public Channel(Channel[] ch. tail=null.next=new QueLink(obj).// pop the first item. tail=tail.getInputStream()).int i. private Socket s.i++) if(ch[i]!=null) ch[i]. private int thisChannel. try{ in=new DataInputStream(s. } class QueLink { public QueLink (Object obj) { this.next.i<MAX_CLIENTS.output(packet). public Object obj.pop(). else{ tail.ch=ch. if (head==null)tail=null. } class Channel implements Runnable{ private boolean isRunning=false.obj. this. } notify(). private Queue que. private Channel[] ch. head=head.){ packet=(byte[])que. for(.obj=obj.next.322 CURS 26 public void run(){ byte[] packet.Queue q){ this. } } } class Queue{ public synchronized Object pop() { while(head==null){ try{ wait().s=s. return obj. thisChannel=i.Socket s. } public synchronized void push(Object obj) { if(head==null)head=tail=new QueLink(obj).. private Thread receiver. for(int i=0. } public QueLink next. next=null. } catch(IOException ex){ . que=q. // wake up blocked threads } private QueLink head=null. // block until we get an item }catch(InterruptedException e){} } Object obj=head. private DataInputStream in.

class in timpul servirii a trei clienti telnet conectati pe portul 2222. receiver=null.toString()+")"). buffer[length]='\r'. 323 } } public void start(){ receiver=new Thread(this).gc(). } } } } class Packet{ public static byte[] newPacket(String msg){ byte[] buffer. } private void stop(){ ch[thisChannel]=null."). } public void output(byte[] packet){ try{ s.PROGRAMARE IN JAVA . return buffer.stop().toString()).write(packet). buffer=new byte[length+2]. que.out.stop().push(Packet.Note de curs System.out. } } In figura 26.println("Received '"+msg+ "' on channel "+thisChannel).buffer. }else{ System.println("Connection "+thisChannel+ " closed by client. isRunning=true.start().out. receiver.println("Error opening input stream: "+ ex. .0). while(isRunning){ try{ if((msg=in. } } public void run(){ String msg="".stop(). receiver.5 sunt prezentate rezultatele afisate de programul TCPServer.println("Connection "+thisChannel+ " closed by client. isRunning=false.out. msg.setDaemon(true).println("Error writing packet to channel "+ thisChannel+".getBytes(0. } }catch(IOException ex){ System."). //System. int length=msg. } catch(IOException ex){ System.getOutputStream(). buffer[length+1]='\n'. } public void finalize(){ receiver.newPacket(msg)).readLine())!=null){ System.length(). isRunning=false.length.out. ("+ex.

private DataOutputStream out. out.awt. import java. s=null.close().*.324 CURS 26 Fig.gc(). } return super. private TextField send=new TextField(30). . btnStat=false. System.close(). Object o){ String msg. return true. s.net.handleEvent(e).id==e.5 – Activitatea unui server TCP/IP multithred Aplicatia client este redata mai jos: import java. private boolean btnStat.*.setEditable(false).add(btn). private DataInputStream in. private Button btn.close(). recv=new TextField(30). } public boolean action(Event e. import java. show(). recv.WINDOW_DESTROY){ quit(). } public boolean handleEvent(Event e){ if(e.26. resize(220. private Socket s.target==btn) if(btnStat){ try{ in.*. public Client(){ super("Aplicatie Client").115). if(e. add(send). setLayout(new FlowLayout()).add(recv). class Client extends Frame{ private final static int PORT=2222. btn=new Button("Start").io.

}catch(IOException ex){} }else{ try{ s=new Socket("141. client.btn.close().btnStat){ try{ if((msg=client. send.getText().close().setLabel("Start").setLabel("Start").setText(""). client. btnStat=true.btn. client. btn.btnStat=false. }catch(IOException e){} } } } } 325 . in=new DataInputStream(s. } private void quit(){ System.close().close().setText("").exit(0).btnStat=false.close().recv.out.recv. client.PROGRAMARE IN JAVA .recv. btn. out. else{ client.."). client. client. client.in. client. } public static void main(String[] args){ String msg="". System.s=null.gc().dispose().85.10".newPacket(msg)).out. } } catch(IOException ex){ try{ client.getOutputStream()).s. client. }catch(IOException ex){} } else{ try{ msg=send.gc().println("Client shut down.) if(client.System.in. for(.Note de curs btnStat=false.write(Packet.setText(msg).. out=new DataOutputStream(s.in.setLabel("Stop").PORT).. client. client.close(). System.setText("").44.getInputStream()). } catch(IOException ex){} } return true. Client client=new Client(). hide().s=null.s. client.out.setLabel("Start").readLine())!=null) client.

threadul receptor este chiar thredul principal iar cel emitator este threadul AWT. Pentru receptionarea unei datagrame UDP trebuie de asemenea creat un obiect din clasa DatagramPacket in care datagrama receptionata sa fie inscrisa. port – portul la care trebuie livrata datagrama.net ofera instrumentele necesare comunicatiei pe baza acestui protocol. Pentru crearea unei datagrame se foloseste constructorul clasei: public DatagramPacket(byte[] ibuf.26.6 – Aplicatii client-server TCP Asa cum am vazut. int length. length . iaddr – adresa IP a destinatarului. Ferestrele afisate de trei aplicatii client si mesajele afisate de server sunt prezentate in figura 25. instante ale clasei DatagramSocket.6. la nivelul transport. ¾ public int getPort() – intoarce portul UDP pe care s-a receptionat datagrama. Ea permite atat crearea de datagrame UDP cat si extragerea dintr-o datagrama receptionata a datelor mesajului. int port) – unde ibuf este un tablou de octeti continand datele mesajului.326 CURS 26 In aceasta aplicatie. Constructorul folosit in acest caz este: public DatagramPacket(byte[] ibuf. pe langa protocolul TCP este definit ca alternativa mai eficienta dar mai putin robusta protocolul UDP.lungimea acestuia. Astfel pentru crearea datagramelor este prevazuta clasa DatagramPacket. int length) – unde ibuf este un tablou de octeti in care se vor inscrie datele mesajului iar length – numarul de octeti ce trebuiesc copiati din datagrama UDP receptionata in acest buffer. adresei IP a expeditorului si a meta-informatiei continute. Socluri UDP Fig. ¾ public byte[] getData() – intoarce o referinta la tabloul de octeti de date. InetAddress iaddr. Operatiile de transmisie si receptie a datagremelor UDP este indeplinita de obiecte de tip soclu UDP. Aceasta defineste urmatorii constructori: . ¾ public InetAddress getAddress() – intoarce adresa IP a expeditorului. Pachetul java. Clasa DatagramPacket prevede in plus metode pentru obtinerea meta-informatiei continute de datagrama UDP receptionata: ¾ public int getLength() – intoarce lungimea in octeti a informatiei utile din datagrama.

){ dp=new DatagramPacket(new byte[2].println("Waiting request. fiecare cu adresa IP diferita. public static void main(String[] args)throws Exception{ DatagramPacket dp.. System. Clasa DatagramSocket defineste urmatoarele metode: public void send(DatagramPacket p) ) throws IOException – care expediaza in reteaua IP datagrama transmisa ca parametru.util. Acesta asteapta sosirea pe portul 2222 a unei cereri din partea unei aplicatii client. Din datagrama UDP primita ca cerere extrage adresa calculatorului pe care ruleaza aplicatia client si portul la care aceasta va astepta raspunsul. construieste un soclu UDP pe portul cu numarul port si adresa IP a interfetei de retea specificate. Aplicatia client-server prezentata in continuare exemplifica utilizarea acestor metode: import java.getByName("nexus. public DatagramSocket(int port) throws IOException – construieste un soclu UDP pe portul cu numarul port. class UDPClient{ public final static int PORT=2222. int port.. InetAddress addr=InetAddress.net. public synchronized void receive(DatagramPacket p) ) throws IOException – care asteapta sa fie receptionata din reteaua IP datagrama transmisa pe adresa IP locala a calculatorului si portul soclului UDP. System.getAddress().getPort().getByName("nexus.*. InetAddress localAddr) throws IOException – folosit pentru cazul calculatoarelor cu mai multe interfete de retea. addr=dp. byte[] packet=new byte[64].ro"). Datagrama UDP receptionata este inscrisa in obiectul din clasa DatagramPacket p specificat ca parametru.addr. packet=Packet.newPacket((new Date()).*. Pe aceasta adresa si la acest port trimite o datagrama continand data si ora curenta dupa care reia asteptarea unei noi cereri. System.home. ds.util.packet. DatagramSocket ds=new DatagramSocket(PORT). . import java. public DatagramSocket(int port. byte[] packet.println("Received request from "+ addr.out. InetAddress addr=InetAddress. import java.").length.toString()).*.2).. Aplicatia client are codul sursa de mai jos: import java. } } } Programul de mai sus implementeaza aplicatia server UDP.toString()+":"+port).port).home.toString()). for(.send(dp). class UDPServer{ public final static int PORT=2222.ro").Note de curs 327 public DatagramSocket() throws IOException – construieste un soclu UDP pe un port arbitrar.PROGRAMARE IN JAVA .receive(dp).net. public static void main(String[] args)throws Exception{ DatagramPacket dp. dp=new DatagramPacket(packet.out.out. ds. port=dp.println("Sending date to "+ addr.*.

328 CURS 26 DatagramSocket ds=new DatagramSocket().addr.println("Sending request to "+ addr. } } } Aplicatia client lanseaza la fiecare 10 secunde o cerere de servire prin transmiterea unui pachet gol pe adresa calculatorului server. Mesajele afisate la consola de 2 aplicatii client si aplicatia server.PORT).sleep(10000). ds..out.){ Thread.2.receive(dp). dp=new DatagramPacket(Packet.send(dp). System.packet.toString()+".println("Current date:"+ (new String(dp. sunt redate in figura 26.6 – Aplicatii client-server UDP .7 Fig. ds.length).out. System. dp=new DatagramPacket(packet.getData(). for(..newPacket("").").0))). Mesajul primit este afisat la consola. Dupa aceea asteapta sosirea datagramei de la server din care extrage mesajul continand data si ora curenta a serverului.. la portul 2222.26.

txt copiat in text4.Software applications</P> <P>. Fig.html acesta va afisa in fereastra sa documentul executand procesarile specificate de marcajele prevazute in textul acestuia (figura 28.1).Custom Internet/Intranet client-server applications</P> <P><B>Call Now!</B></I> Incarcand cu browserul MSIE fisierul text4.Networking</P> <P>.28.gif> <P>Javamatic</P> <P>Internet/Intranet Software</P> <P></P> <P><B>SERVICES</B></P> <P><I>.html: <IMG SRC=javamatic.IT Professional Services</P> <P>.html afisat de MSIE La afisarea acestui document.System Integration</P> <P>.Note de curs 341 Curs 28 Structura documentelor HTML Fie fisierul text3. De fapt marcajele convenite la .1 – documentul text4.class elaborat de noi.Consulting hw/sw</P> <P>. browserul a facut exact aceleasi operatii de procesare a textului ca si programul Doc.PROGRAMARE IN JAVA .

</tt></center> <br> <center> <table border=3> <tr> <td> <a href="gallery/index.html"><img border=0 src="images/williams.html continand textul din listingul 28. .Cybertyse. numit si sursa.jpg" alt="Virtual Gallery"></CENTER> <br> <center><tt><h2>Welcome to the Cybertise Virtual Gallery. or friends. romulanii si ferengii dar si celelalte fiinte la fel de inteligente si conectate la Internet din Galaxie sa aibe informatii despre misiunea echipajului sau . Ceea ce face ca acest document sa fie afisat intr-o forma mult mai atragatoare sunt codurile de marcaj sau tag-urile ( acele portiuni din text scrise intre perechi de paranteze unghiulare < > ) care controleaza formatarea si aspectul reprezentarii sale in fereastra navigatorului.gif" alt="Ken Williams"></a> </td> <td> <a href="gallery/index2.342 CURS 28 scrierea programului nu au fost alese arbitrar. Se editeaza un fisier cu numele Prima..html"><img border=0 src="images/wing.</center> <br> <center><tt>Just click on a designer's name and away you go. and there are more to come in the future.9 este redat in listingul 28.2. fun..</center> <center>All of the graphics on this Web site were done by Cybertise (except for obvious icons). comenzi date browserului privind structura documentului si modul de afisare al textului incadrat de aceste marcaje. Pentru aceasta folositi un program de editare de text. a carui reprezentare apare in figura 27. Listing 28.jpg" alt="Chris Wing"></a> </td> </tr> </table> </center> </body> </html> Se vede ca este vorba de un simplu fisier text.</h2></tt></center> <center>This is a collection of design and artwork done by Cybertise artists for clients. Pentru a personaliza intr-un fel exemplul nostru. s-a hotarat sa creeze pe WWW o pagina Web a acesteia pentru ca toti klingonii. Documentul HTML original. capitanul navei spatiale Entreprise.1.1 . de exemplu Notepad din accesoriile Windows. fiind chiar cele din setul de marcaje HTML. Jean-Luc Picard. Cea mai eficienta cale de a invata cum se construieste o pagina de Web este de a crea una. Acestea reprezinta de fapt niste instructiuni. vom presupune ca fiind conectat la Internet prin sistemul subspatial de comunicatii galactice la mare distanta.html <HTML> <HEAD> <TITLE>Cybertise's Virtual Gallery</TITLE> </HEAD> <BODY BGCOLOR=#FFFFFF TEXT=#000000 LINK=#0000FF VLINK=#008000 ALINK=#FFFF00> <CENTER><img src="images/gallery2.

2 Prima pagina Web a capitanului Picard Marcaje de structura Sa analizam un pic documentul HTML creat de noi. HEAD / TITLE BODY Fig. De asemenea caracterele SPATIU. browserul nu va face nici o diferenta la interpretarea acestora. marcajele iesind astfel in evidenta in textul documentului HTML. USS Entreprise. data editat fisierul Prima. acesta trebuie sa inceapa cu marcajul <HTML> si sa se termine cu marcajul complementar </HTML>: <HTML> … Continutul documentului … . structura acestuia devenind astfel mai evidenta. incarcandu-l cu browserul favorit. contine diferite marcaje care. Observam ca el. in acest caz.Prima. Totusi. pe langa textul ce va fi afisat de browser. 1701-D. BODY. </body> </html> 343 Observati ca nu are importanta daca cuvintele cheie.Home Page</TITLE> </HEAD> <BODY> Welcome to Galaxy class starship.2. ce apar in marcajele HTML < > sunt scrise cu litere mari sau mici.html <HTML> <HEAD> <TITLE>USS Entreprise . cum ar fi HTML. TAB si ENTER sunt ignorate de browser. definesc structura documentului. veti obtine o imagine similara cu cea din figura 28.PROGRAMARE IN JAVA . folosirea literelor mari este recomandata. Putem scrie dupa preferinta <HTML> sau <html>. TITLE.28.2 . Astfel indiferent de continutul documentului HTMl.html.Note de curs Pentru inceput el a editat urmatorul document HTML: Listing 28.

Acest text este afisat de majoritatea browserelor in bara de titlu a ferestrei aplicatiei ca in figura 2. Antetul este un bloc de text delimitat de perechea <HEAD> si </HEAD>. Majoritatea marcajelor limbajului HTML se folosesc la fel ca si cele de mai sus. Unul.antetul documentului si corpul acestuia.3.344 </HTML> CURS 28 Aceste marcaje definesc inceputul respectiv sfarsitul documentului HTML. Documentele HTML sunt structurate in doua sectiuni . avind acelasi nume ca si primul dar precedat de un caracter “slash” (/) sfarsitul blocului. de exemplu <…>. Corpul documentului este delimitat de marcajele <BODY> si </BODY>: <HTML> <HEAD> … Antetul documentului … </HEAD> <BODY> … Corpul documentului … </BODY> </HTML> Antetul documentului HTML poate sa contina la rindul sau mai multe elemente dar obligatoriu trebuie sa fie prevazut numai titlul acestuia . perechi. In figura 28.3 este cel din Listingul 28. Crearea subtitlurilor Limbajul HTML prevede marcaje pentru a crea subtitluri de diverse dimensiuni. Ca si marcajele discutate inainte marcajele de subtitluri se termina cu marcajele pereche de incheiere </H1> pana la </H6>. fiind dificil de citit. <HTML> <HEAD> <TITLE> … Titlul documentului … <\TITLE> </HEAD> <BODY> … Corpul documentului … </BODY> </HTML> Corpul documentului poate sa contina la rindul sau mai multe elemente pe care le vom analiza in continuare. marcheaza inceputul unui bloc de text iar perechea sa </…>.1. Sunt posibile sase niveluri de subtitluri de la cele mai mari marcate la inceput cu <H1> pana la cele mai mici marcate cu <H6>.un text incadrat de marcajele pereche <TITLE> si </TITLE>. Documentul sursa HTML corespunzator paginii afisate in figura 28. Pe majoritatea sistemelor subtitlurile de nivel 6 au literele foarte mici. In acest listing se observa ca marcajele de sfirsit de subtitlu au fost .3 se poate observa efectul introducerii subtitlurilor in document.

</H4> <H5> Stardate 48030.html <HTML> <HEAD> <TITLE>USS Entreprise . AND NEW CIVILISATIONS. is a Galaxy class starship built at the Utopia Plannitia Fleet Yards above Mars. and is currently under command of Captain Jean-Luc Picard. marcajele de sfarsit sunt mai usor de vazut in listing.Note de curs 345 aliniate prin introducere de caractere TAB. vom constata ca browserul a ignorat la afisarea textului despartirea pe randuri facuta de capitanul Picard si a facut propria sa despartire in functie de latimea ferestrei de afisare. as well as in several crucial incidents defending the security of the Federation. Astfel in listing apare textul privind nava Entreprise pe 8 randuri iar browserul o afiseaza numai pe 5: textul sursa: The USS Entreprise.Headings. USS Entreprise.28. is a Galaxy class starship .Home Page</TITLE> </HEAD> <BODY> <H1> STAR TREK </H1> <H2> THE NEXT GENERATION </H2> <H3> Welcome to Galaxy class starship. Listing 28. This latest starship is Starfleet‘s flagship and has already distingueshed in an impressive number of significant missions of exploration. NCC -1701-D.4581 </H5> <H6> This page is under heavy construction! </H6> The USS Entreprise.3 Crearea subtitlurilor Paragrafe Analizand cu atentie listingul si imaginea afisata.3 . NEW WORLDS. 1701-D </H3> <H4> TO EXPLORE STRANGE.TO BOLDLY GO WHERE NO ONE HAS GONE BEFORE. Prin aceasta nu este influentat cu nimic modul de afisare al paginii dar se imbunatateste lizibilitatea programului. It was comissioned in 2363. </BODY> </HTML> Fig.PROGRAMARE IN JAVA . NCC -1701-D. TO SEEK OUT NEW LIFE.

Home Page</TITLE> </HEAD> <BODY> <H1> STAR TREK </H1> <H2> THE NEXT GENERATION </H2> <H3> Welcome to Galaxy class starship. It was comissioned in 2363.Despartirea textului in paragrafe Delimitarea randurilor .</P> <P>This latest starship is Starfleet‘s flagship and has already distingueshed in an impressive number of significant missions of exploration. and is currently under command of Captain Jean-Luc Picard. mai mare. USS Entreprise. as well as in several crucial incidents defending the security of the Federation. fortand browserul sa afiseze textul paragrafului de la inceput de rand.html <HTML> <HEAD> <TITLE>USS Entreprise . Listing 28.4581 </H5> <H6> This page is under heavy construction! </H6> <P>The USS Entreprise.28. NCC -1701-D. TO SEEK OUT NEW LIFE. and is currently under command of Captain Jean-Luc Picard.28. is a Galaxy class starship built at the Utopia Plannitia Fleet Yards above Mars.Paragraphs. Daca fereastra de afisare ar fi fost mai lata. It was comiissioned in 2363. AND NEW CIVILISATIONS.</P> </BODY> </HTML> Fig. 1701-D </H3> <H4> TO EXPLORE STRANGE. textul afisat de browser: The USS Entreprise.4 arata modul de introducere si efectul acestor marcaje intr-un document HTML.This latest starship is Starfleet‘s flagship and has already distingueshed in an impressive number of significant missions of exploration.TO BOLDLY GO WHERE NO ONE HAS GONE BEFORE. NEW WORLDS.346 CURS 28 built at the Utopia Plannitia Fleet Yards above Mars. as well as in several crucial incidents defending the security of the Federation. Pentru a putea desparti textele din corpul documentului HTML in paragrafe. is a Galaxy class starship built at the Utopia Plannitia Fleet Yards above Mars. Listingul 28.4 . It was comissioned in 2363. NCC -1701-D. and is currently under command of Captain Jean-Luc Picard. numarul de randuri al textului ar fi fost mai mic iar daca ar fi fost mai ingusta .4 .4 si Fig. This latest starship is Starfleet‘s flagship and has already distingueshed in an impressive number of significant missions of exploration. </H4> <H5> Stardate 48030. se folosesc marcajele <P> si </P> care delimiteaza continutul unui paragraf. as well as in several crucial incidents defending the security of the Federation.

5 . and is currently under command of Captain Jean-Luc Picard.LineBreaks. NCC -1701-D.4581 </H5> <H6> This page is under heavy construction! </H6> The USS Entreprise. </BODY> </HTML> Fig.Note de curs 347 Acum textul arata ceva mai bine. Problema este ca spatiul dintre cele doua fragmente de text este cam mare.TO BOLDLY GO <BR> WHERE NO ONE HAS GONE BEFORE.5 .28.<BR> This latest starship is Starfleet‘s flagship and has already distingueshed in an impressive number of significant missions of exploration.5 respectiv in Fig.5. se foloseste marcajul <BR> (Break line). as well as in several crucial incidents defending the security of the Federation. AND NEW CIVILISATIONS.PROGRAMARE IN JAVA . TO SEEK OUT <BR> NEW LIFE. Listing 28. USS Entreprise. It was comissioned in 2363. </H4> <H5> Stardate 48030.Home Page</TITLE> </HEAD> <BODY> <H1> STAR TREK </H1> <H2> THE NEXT GENERATION </H2> <H3> Welcome to Galaxy class starship. is a Galaxy class starship built at the Utopia Plannitia Fleet Yards above Mars. NEW WORLDS.html <HTML> <HEAD> <TITLE>USS Entreprise .Delimitarea liniilor . Utilizarea acestui marcaj si rezultatul obtinut se vede in listingul 28.28. 1701-D </H3> <H4> TO EXPLORE STRANGE.este un marcaj vid. Marcajul <BR> nu are un marcaj pereche </BR> . Daca vreti ca browserul sa intrerupa linia de text afisata dar sa nu lase spatiu liber pana la linia urmatoare.

in punctul in care este introdus in text. marcajul <HR>nu are o pereche </HR> (marcaj vid).Rules.4581 </H5> <H6> This page is under heavy construction! </H6> <HR> The USS Entreprise. is a Galaxy class starship built at the Utopia Plannitia Fleet Yards above Mars. and is currently under command of Captain Jean-Luc Picard. </H4> <HR> <H5> Stardate 48030.348 CURS 28 Adaugarea unei linii de separatie Acum ca am lipit intre ele cele doua paragrafe.<BR> This latest starship is Starfleet‘s flagship and has already distingueshed in an impressive number of significant missions of exploration. 1701-D </H3> <H4> TO EXPLORE STRANGE. determina o trecere la un rand nou . as well as in several crucial incidents defending the security of the Federation.html <HTML> <HEAD> <TITLE>USS Entreprise . NEW WORLDS.Home Page</TITLE> </HEAD> <BODY> <H1> STAR TREK </H1> <H2> THE NEXT GENERATION </H2> <HR> <H3> Welcome to Galaxy class starship.6. O linie orizontala care sa separe vizual subtitlurile de text ar face ca pagina sa arate mai organizat. subtitlurile nu arata prea bine contopindu-se cu textul paginii.6 respectiv in Fig. Listing 28. astfel de linie (rigla) se introduce cu marcajul <HR> (Horizontal Rule). It was comissioned in 2363.TO BOLDLY GO <BR> WHERE NO ONE HAS GONE BEFORE. Utilizarea acestui marcaj si rezultatul obtinut se vede in listingul 28. Ca si <BR>. TO SEEK OUT <BR> NEW LIFE. NCC -1701-D. Aceasta nu numai determina browserul sa deseneze o linie orizontala pe ecran dar.28. AND NEW CIVILISATIONS. <HR> </BODY> </HTML> . USS Entreprise.6 .

</I> </H4><HR> <H5> <U>Stardate 48030.USS Entreprise. In listingul 28. <I></I> pentru italic.Home Page</TITLE></HEAD> <BODY> <H1> <B><I>STAR TREK</I></B></H1> <H2> <B><I>THE NEXT GENERATION</I></B></H2><HR> <H3> <I>Welcome to Galaxy class starship.PROGRAMARE IN JAVA .7 prezinta aceasta pagina Web si documentul sursa HTML corespunzator. Capitanul Picard a folosit in pagina sa Web imbunatatita marcajele <B></B> pentru stilul Bold(accentuat). in textul documentului HTML este util sa fie introduse comentarii.->.Note de curs Fig. is a Galaxy class starship built at the <I>Utopia Plannitia Fleet Yards</I> above Mars. Fig.Styles.<BR>This latest starship is <B>Starfleet</B>‘s flagship and has already distingueshed in an impressive number of significant missions of exploration. Created on stardate 48030.6 . data si natura modificarilor aduse in timp acestuia.TO BOLDLY GO <BR> WHERE NO ONE HAS GONE BEFORE. and is currently under command of Captain JeanLuc Picard. Listing 28. NCC -1701-D</B>.7 si Listingul 28. Marcajul folosit pentru a indica inceputul comentariului este <!--. 1701-D </I></H3> <H4> <I>TO EXPLORE STRANGE. Pot fi astfel inscrise informatii privind autorul documentului.28.This is the new and iprouved HTML page of USS Entreprise 1701-D For klingons and Romulans use only. It was comissioned in 2363. Sfirsitul comentariului se indica cu marcajul . NEW WORLDS. Stilul textului afisat La procesoarele de texte cum ar fi Microsoft Word for Windows pentru a imbunatati impactul vizual al textelor editate avem posibilitatea de a alege corpuri de litera diferite (fonte) si stiluri de afisare a acestora (Bold/ Italic/Underline) In cazul HTML nu putem alege un anume corp de litera dar putem totusi specifica stilul in care textul va fi afisat. .7 .4581 by Captain Jen-Luc Picard.4581</U></H5> <H6> This page is under heavy construction!</H6><HR> The <B>USS Entreprise. adica blocuri de text care nu sunt afisate de browser dar pot servi pentru o mai buna documentare a documentului.7 se poate vedea utilizarea acestor marcaje. as well as in several crucial incidents defending the security of the <B>Federation</B>.html <HTML> <!-.28.<HR> </BODY> </HTML> . si <U></U> pentru Underline(subliniat). TO SEEK OUT <BR> NEW LIFE.-> <HEAD><TITLE>USS Entreprise . alte explicatii privind documentul respectiv. AND NEW CIVILISATIONS.Utilizarea riglelor 349 Comentarii Pe langa informatia ce urmeaza a fi afisata.

html <HTML> <!-. marcajul imagine fiind … <IMG SRC="StarTrek.gif"> … Rezultatul obtinut la afisarea acestui document de catre browser este redat in figura 28.gif"> … Daca fisierul imagine s-ar fi gasit intr-un director diferit de cel al fisierului sursa.350 CURS 28 Fig.8 . marcajul ar fi trebuit sa contina si calea pana la fisier.This is the new and iprouved HTML page of USS Entreprise 1701-D . O imagine este continuta de un fisier intr-un format dat. Majoritatea browserelor recunosc formatele GIF si JPEG.html.Images.gif . marcajul ar fi fost: … <IMG SRC="C:\Images\Gif_uri\StarTrek. In listingul 28.7 -Stiluri de litere Imagini Pentru a face pagina de Web mai atractiva ea poate fi prevazuta cu imagini.8: Listing 28.28. Astfel daca fisierul se gaseste in directorul C:\IMAGES\GIF_URI. Pentru a adauga o imagine paginii de Web se foloseste marcajul <IMG> avand sintaxa <IMG SRC=”fisier_imagine”>.8 se vede cum a folosit capitanul Picard acestui marcaj pentru a adauga la pagina Web a navei sale imaginea continuta de fisierul StarTrek. In acest caz fisierul se gaseste in acelasi director cu fisierul Images.

as well as in several crucial incidents defending the security of the <B>Federation</B>.4581 by Captain Jen-Luc Picard. AND NEW CIVILISATIONS.TO BOLDLY GO<BR> WHERE NO ONE HAS GONE BEFORE. 1701D<BR> TO EXPLORE STRANGE.</I></B> </H3><HR> The <B>USS Entreprise.gif"><I>Stardate 48030.USS Entreprise. Created on stardate 48030. NCC -1701-D</B>.<BR> This latest starship is <B>Starfleet</B>‘s flagship and has already distingueshed in an impressive number of significant missions of exploration.4581</I></H5><HR> <H3> <B><I>WELCOME TO GALAXY CLASS STARSHIP. .8 Imagine in pagina Web . and is currently under command of Captain JeanLuc Picard. TO SEEK OUT<BR> NEW LIFE.Note de curs For klingons and Romulans use only.<HR> </BODY> </HTML> Fig. NEW WORLDS.28. It was comissioned in 2363.PROGRAMARE IN JAVA . is a Galaxy class starship built at the <B><I>Utopia Plannitia Fleet Yards</I></> above Mars.-> <HEAD> <TITLE>USS Entreprise .Home Page</TITLE> </HEAD> <BODY> 351 <H5> <IMG SRC="StarTrek.

documentul HTML corespunzator va fi cel din listingul 28.4581 by Captain Jen-Luc Picard.000 light years 25 years To nearby Galaxy 2.Randul 2 .1 Warp speed table Speed miles hour per Times speed of light Earth moon 250. Ramine un spatiu nefolosit in dreapta imaginii.440.000 miles Warp factor 6 263 Bilion 382 0.096 years 7.-> <TR> <TD>Speed</TD><TD>miles per hour</TD><TD>Times speed of light</TD> <TD>Earth to moon</TD><TD>Across solar system</TD> <TD>Between two nearby stars</TD><TD>Across one sector</TD> <TD>Across Federation</TD><TD>To nearby Galaxy</TD> </TR> <!-.000 miles</TD> <TD>7.000.</TD> pentru celulele unui rand (Table Data).9 Tabel 28.1.Antetul tabelului .-> <TH>Warp speed table</TH> <!-. Pentru ca tabelul sa aibe margini vizibile marcajul de inceput de tabel va fi <TABLE BORDER> De exemplu pentru a introduce intr-o pagina Web tabelul 28.000 light years</TD> </TR> <!-.00342634 seconds to Across system solar Between two nearby stars 5 light years Across one sector 20 light years 18 days Across Federation 10.00342634 seconds</TD><TD>2 minutes</TD><TD>5 days</TD> <TD>18 days</TD><TD>25 years</TD><TD>5.--> <HEAD> <TITLE>Warp speed table</TITLE> </HEAD> <BODY> <TABLE BORDER> <!-.000 miles 2 minutes 5 days Listing 28.Warp speed table with borders Created on stardate 48030.000.-> <TR> <TD>Warpfactor 6</TD><TD>263 Bilion</TD><TD>382</TD> <TD>0.096 years</TD> </TR> </TABLE> </BODY> </HTML> .000 miles</TD><TD>5 light years</TD> <TD>20 light years</TD><TD>10. Lucrurile pot fi ameliorate folosind marcajele pentru tabele.000 light years</TD> <TD>2.000.Randul 3 . In cadrul blocului de text incadrat de aceste doua marcaje se definesc optional antetul si celulele tabelului cu ajutorul marcajelor <TH>.</TH> pentru antet (Table Heading). <TR> .-> <TR> <TD></TD><TD></TD><TD></TD><TD>250.000 light years 5.Randul 1 .000.440. totusi imaginea este prost amplasata in raport cu textul.</TR> pentru delimitarea unui rand al tabelului (Table Row) si <TD>.html <HTML> <!-. HTML foloseste marcajele <TABLE> si </TABLE> pentru a defini un tabel.9 .352 CURS 28 Tabele Desi aduce un plus de culoare in pagina Web.WarpSp.

</I></B><H3> </TD> </TR> </TABLE> <HR> <H5><B><I>Stardate 48030. TO EXPLORE STRANGE.-> <HEAD> <TITLE>USS Entreprise .Tabelul are un singur rand cu doua celule si este fara margini vizibile --> <TD> <IMG SRC="StarTrek.4581</I></B><H5><HR> The <B>USS Entreprise. NCC -1701-D</B>. It was comissioned in 2363.10 .28. procedeu la care a apelat si capitanul navei Entreprise in listingul 28.html <HTML> <!-. TO SEEK OUT NEW LIFE.prima celula contine imaginea --> <TD> <!-.a doua celula contine textul de bun venit--> <H3><B><I>WELCOME TO GALAXY CLASS STARSHIP. using tables and images.Tables. and is currently under command of Captain JeanLuc Picard. AND NEW CIVILISATIONS.10. Listing 28. of USS Entreprise 1701-D. Folosind acest mecanism poate fi aliniata o imagini cu un bloc de text in celule de tabel alaturate.10 pentru a alinia imaginea cu mesajul de salut. Created on stardate 48030.USS Entreprise 1701-D. is a Galaxy class starship built at the <B><I>Utopia Plannitia Fleet Yards</I></> above Mars.gif"></TD> <!-.Tabel cu margini vizibile In celulele tabelului poat fi introduse blocuri de text sau imagini.TO BOLDLY GO WHERE NO ONE HAS GONE BEFORE.Note de curs Rezultatul incarcarii acestui document de catre browser este cel din figura 28.PROGRAMARE IN JAVA .4653 by Captain Jen-Luc Picard.9 353 Fig.<BR> This latest starship is <B>Starfleet</B>‘s flagship and has already distingueshed in an impressive number of significant missions of . . rezultand pagina Web din figura 28.This is the last release of HTML page.Home Page</TITLE> </HEAD> <BODY> <TABLE> <TR><!-. NEW WORLDS.9 .

10 Utilizarea tabelelor pentru alinierea imaginii cu textul . as well as in several crucial incidents defending the security of the <B>Federation</B>.354 CURS 28 exploration.28.<HR> </BODY> </HTML> Fig.

Hiperlegaturile se bazeaza pe marcajul HTML tip ancora <A>. puse in evidenta in textul paginii printr-o culoare distincta.</A>(Anchor) avand sintaxa: … <A HREF =”#zona”>Text_evidentiat</A> … Aceasta este o trimitere catre o zona din document marcata la randul sau cu o ancora avand sintaxa: … <A NAME=”zona”> … Text_evidentiat este textul care va apare in pagina colorat distinct si subliniat. TO EXPLORE STRANGE. In plus culoarea hiperlegaturii se schimba pentru ca utilizatorul sa stie ca a “vizitat-o” deja cel putin odata.Home Page</TITLE> </HEAD> <BODY> <TABLE> <TR><!-.TO BOLDLY GO .Note de curs 355 Curs 29 Ancore si legaturi Spatiul de afisare in fereastra browserului este limitat. folosite de utilizator pentru a se “teleporta” de la o zona la alta. Utilizatorul poate “naviga” prin document clicaind cu mouseul pe hiperlegaturi. regasirea unui anume subiect prin cautare in toata pagina este dificila.Tabelul are un singur rand cu doua celule si este fara margini vizibile --> <A NAME="TOP"> <TD> <IMG SRC="StarTrek.PROGRAMARE IN JAVA .html <HTML> <HEAD> <TITLE>USS Entreprise . NEW WORLDS.pagini interactive organizate cu ajutorul hiperlegaturilor. Acest mecanism este cel care transforma documentele HTML din simple texte in hipertexte .Links. Este ca si cand am avea o carte fara cuprins pe care am dori sa o deschidem la un anumit capitol.prima celula contine imaginea --> <TD> <!-.1 . AND NEW CIVILISATIONS. Daca informatia continuta in document este mare. Listing 29. TO SEEK OUT NEW LIFE.a doua celula contine textul de bun venit--> <H3><B><I>WELCOME TO GALAXY CLASS STARSHIP. HTML permite organizarea documentului prin definirea a hiperlegaturilor.gif"></TD> <!-. Listingul 29.1 arata modul de folosire a hiperlegaturilor in cadrul documentului HTML.USS Entreprise 1701-D. Pentru aceasta ar trebui sa o rasfoim cautand titlul capitolului dorit.1 si figura 29. browserul deruland automat pagina pana cind informatia asociata acestora apare in fereastra.

</P> <P>The Galaxy class starship represents Starfleet's most sophisticated achievement in multimission ship systems design.02 x 10¦K. Many of these responsibilities are best carried out with relatively small.2. Independent impulse propulsion system of choice for primary hull to include but not be limited to YPS 8055 fusion drive motors.000. NCC -1701-D</B>. warp field geometry to incorporate modified 55¡ Z-axis compression characteristics on forward warp lobe for increased peak transitional efficiency. and with it the Federation itself. and is currently under command of Captain JeanLuc Picard. Yet there continues to be an ongoing need for a small number of larger.</P> <P>These duties range from relatively mundane domestic and civil missions.</P> <A HREF="#TOP">Go to top</A><HR> <A NAME="MISS"> <H4>MISSION</H4> <P> Ability to operate independent of starbase refurbishment for extended periods. Engine systems of choice to include but are not limited to at least two YPS 8063 fusion drive motors. multimission vehicles that are capable of implementing the complete range of Starfleet's objectives.650 cochranes.000 cochrane-hours between neutron purge refurbishment.56:1 ratio of separation to maximum field strength.4581</I></B><H5><HR> The <B>USS Entreprise. Life cycle of all primary coil elements to meet or exceed 1. Fifth-phase dilithium controlled matter/antimatter reactor primary power. Independent exploration mode capability of seven Standard years at nominal Warp 6 velocity for docked configuration.<HR> <A HREF="#MISSION_OBJ"> MISSION OBJECTIVES</A><BR> <A HREF="#SPECS">SPECIFICATIONS</A><HR> <A NAME="MISSION_OBJ"> <H3> MISSION OBJECTIVES FOR GALAXY CLASS PROJECT</H3> <P>Starfleet has long been charged with a broad spectrum of responsibilities to the citizens of the Federation and to the lifeforms of the galaxy at large. to cultural contact and diplomacy. to our primary mission of exploration and research. All units to be equipped with subspace driver accelerators. Ability to maintain speeds of up to Warp 9.356 CURS 29 WHERE NO ONE HAS GONE BEFORE. field output not less than 180 millicochranes at 1. Secondary (impulse) propulsion system to provide sublight velocities up to and including 0. peak transitional surge reserve to exceed 4. Reactor modules to be fieldreplaceable. specialized ships. Warp nacelle center-lines to conform to 2.</I></B><H3></TD></TR> </TABLE><HR> <H5><B><I>Stardate 48030. It was comissioned in 2363. This need has in fact grown as the volume of relatively unexplored space within Federation influence continues to expand.</P> <A HREF="#TOP">Go to top</A><HR> <A NAME="SPECS"> <H3>SPECIFICATIONS</H3> <A HREF="#PROP"> PROPULSION</A><BR> <A HREF="#MISS"> MISSION</A><BR> <A HREF="#ENVC"> ENVIRONMENT/CREW </A><BR> <A HREF="#TACT"> TACTICAL </A><BR> <A HREF="#DSGN"> DESIGN LIFE </A><BR> <A HREF="#TOP">Go to top</A><HR> <A NAME="PROP"> <H4>PROPULSION</H4> <P>Sustainable cruise velocity of Warp Factor 9.200.000 cochrane-hours between neutron purge refurbishment. so do Starfleet's duties.Sustainable field output to exceed 1.225% of nominal output (170 ns phase).0. is a Galaxy class starship built at the <B><I>Utopia Plannitia Fleet Yards</I></> above Mars. .6 for periods of up to twelve hours.<BR> This latest starship is <B>Starfleet</B>‘s flagship and has already distingueshed in an impressive number of significant missions of exploration. Secondary coil elements to meet or exceed 2.1. Warp driver coils efficiency to meet or exceed 88% at speeds up to Warp 7.92 lightspeed (c). as well as in several crucial incidents defending the security of the <B>Federation</B>. As the volume of explored space continues to grow. Minimum efficiency of 52% to be maintained through Warp 9. to defense.

or L environmental conditions. provisions for 10% of quarters to support Class H.</P> <P>Facilities to support Class M environmental range in all individual living quarters. </P> <P>Tactical systems to include full array of Type X phaser bank elements on both primary and stardrive (battle) sections capable of 5.</P> <P>Ability to support a wide range of mission-related ongoing research and other projects (including sufficient habitable volume and power generation for facilities and operations) without impact on primary mission operations. and L environmental conditions.</P> <P>Ability to support up to 5. <P>Full spectrum EM. with auxiliary system able to provide 65% of primary rating. optical. particle. and quark population analysis sensor capability. capable of warp flight and optimized for combat. and a primary section capable of impulse flight and defensive operations</P> <P>Full independent sublight operational capability for command section in Separated Flight Mode. Twometer diameter gamma ray telescope. depending on specific mission requirements and hardware availability. Upgradable experiment and sensor array design. Additional 2% of living quarters volume to be equipped for Class N and N(2) environmental adaptation.</P> <A HREF="#TOP">Go to top</A><HR> <A NAME="TACT"> <H4> TACTICAL</H4> <P>Defensive shielding systems to exceed 7. All life.</P> <P>Support facilities for auxiliary spacecraft and instrumented probes needed for short-range operations to include at least two independent launch.PROGRAMARE IN JAVA . K. resupply.3(a) levels for EM and nuclear radiation. and full biologic and ecologic studies. subspace flux.000 m® for mission-adaptable facilities including living quarters for mission-specific attached personnel.</P> <P>All habitable volumes to be protected to SFRA-standard 347.000 non-crew personnel for missionrelated operations. gravimetric.02 millicochranes. first cultural contact scenarios.Note de curs 357 Ability to execute deep. Two photon torpedo launchers required for battle section. Such upgrades help insure the continuing usefulness of the ship even though significant advances in technology are anticipated during that time. K. Ability to support both on-board and probe-mounted science instrumentation. assuming approximately five major shipwide system swapouts and upgrades at average intervals of twenty years. Multimode neutrino interferometry instrumentation. Subspace flux differential to be maintained within 0. </P> <P>Space allocation for mission-specific facilities: Habitable area to include 800. All tactical shielding to have full redundancy. Wide-band life sciences analysis capability pursuant to Starfleet life contact policy directive. one auxiliary launcher in primary hull.standard 102.critical systems to be triply redundant.19 for Class M compatible oxygen-breathing personnel.3 x 10° kW primary energy dissipation rate. and repair bays.</P> <A HREF="#TOP">Go to top</A><HR> <A NAME="DSGN"> <H4>DESIGN LIFE</H4> <P>Spaceframe design life of approximately one hundred years.space exploration missions including charting and mapping.1MW maximum single emitter output. Minor refurbishment and upgrade to occur at approximately one-to five-year intervals. Life support modules to be replaceable at major starbase layover to permit vehiclewide adaptation to Class H. </P> <A HREF="#TOP">Go to top</A><HR></BODY></HTML> .</P> <P> Ability to separate into two autonomous spacecraft comprising a battle section.</P> <A HREF="#TOP">Go to top</A><HR> <A NAME="ENVC"> <H4> ENVIRONMENT/CREW</H4> <P>Environmental systems to conform to Starfleet Regulatory Agency (SFRA).

29.1b Fig.358 CURS 29 Fig.1a Fig.29.29.1c .

HTML care joaca un rol similar cu cuprinsului unei carti.HTMLaccesul la acestea facandu-se prin legaturi din documentul principal continut intr-un fisier denumit de exemplu Index.4b.2 este prezentata diagrama legaturilor implementate in documentul HTML din exemplul nostru.3.HTML si Specs.4. In acest caz sintaxa legaturii este: … <A HREF =”document_tinta#zona”>Text_evidentiat</A> … Zona referita de o astfel de legatura se marcheaza cu o ancora avand sintaxa: … <A NAME =”zona”>Text_evidentiat</A> … Structura ansamblului de documente HTML interconectate prin legaturi este redata in figura 29.2 iar al fisierelor MissionObj.4a si 29.HTML si Specs. Astfel in cazul exemplului precedent este mai rational din punct de vedere structural ca informatiile privind obiectivele misiunii si specificatiile navei stelare Entreprise 1701-D sa fie inscrise in doua fisiere distincte denumite MissionObj.HTML in Listingul 29. Continutul documentului Index. Legaturile pot face trimiteri nu numai in cadrul aceluiasi document HTML ci pot referi documente HTML amplasate in alte fisiere.HTML este cel redat in Listingul 29.PROGRAMARE IN JAVA . Explorarea cu navigatorul a acestui pachet de pagini Web este prezentata in figurile 29. Sintaxa pentru o astfel de legatura la un document extern este : … <A HREF =”document_tinta”>Text_evidentiat</A> … Legaturile pot sa refere nu numai un anumit document ci si o pozitie specifica din acesta.3 respectiv 29.Note de curs 359 In figura 29. .

29.HTML Fig.2 Legaturi in documentul Links.360 CURS 29 Fig.3 Structura unui ansamblu de documente HTML interconectate prin legaturi .29.

AND NEW CIVILISATIONS. as well as in several crucial incidents defending the security of the <B>Federation</B>.2 .</P> <P>These duties range from relatively mundane domestic and civil missions.HTML"> MISSION OBJECTIVES</A><BR> <A HREF="Specs.Specs.</P><HR> <A HREF="Index.</I></B><H3></TD></TR> </TABLE><HR> <H5><B><I>Stardate 48030.html <HTML> <HEAD> <TITLE>USS Entreprise . multimission vehicles that are capable of implementing the complete range of Starfleet's objectives.Home Page</TITLE> </HEAD> <BODY> <TABLE> <TR> <TD> <IMG SRC="StarTrek.USS Entreprise 1701-D. This need has in fact grown as the volume of relatively unexplored space within Federation influence continues to expand.PROGRAMARE IN JAVA .HTML #MISS"> MISSION</A><BR> <A HREF=" Specs. specialized ships.html <HTML> <HEAD> <TITLE>USS Entreprise .HTML #ENVC"> ENVIRONMENT/CREW </A><BR> <A HREF=" Specs. and with it the Federation itself.Note de curs 361 Listing 29.<BR> This latest starship is <B>Starfleet</B>‘s flagship and has already distingueshed in an impressive number of significant missions of exploration.HTML #PROP"> PROPULSION</A><BR> <A HREF=" Specs. is a Galaxy class starship built at the <B><I>Utopia Plannitia Fleet Yards</I></> above Mars.gif"></TD> <TD> <H3><B><I> WELCOME TO GALAXY CLASS STARSHIP.MissionObj.html <HTML> <HEAD> <TITLE>USS Entreprise . to cultural contact and diplomacy.HTML #TACT"> TACTICAL </A><BR> <A HREF=" Specs. NCC -1701-D</B>.HTML #DSGN"> DESIGN LIFE </A><HR> </BODY> </HTML> Listing 29.4581</I></B><H5><HR> The <B>USS Entreprise. NEW WORLDS. Yet there continues to be an ongoing need for a small number of larger. As the volume of explored space continues to grow.Index.Mission Objectives</TITLE> </HEAD> <BODY> <H3> MISSION OBJECTIVES FOR GALAXY CLASS PROJECT</H3><HR> <P>Starfleet has long been charged with a broad spectrum of responsibilities to the citizens of the Federation and to the lifeforms of the galaxy at large.HTML">SPECIFICATIONS</A><BR> <A HREF=" Specs.HTML">Go to home page</A> </BODY> </HTML> Listing 29. Many of these responsibilities are best carried out with relatively small. and is currently under command of Captain JeanLuc Picard. TO SEEK OUT NEW LIFE.Specifications</TITLE> </HEAD> <BODY> .</P> <P>The Galaxy class starship represents Starfleet's most sophisticated achievement in multimission ship systems design.3 .<HR> <A HREF="MissionObj. to our primary mission of exploration and research. It was comissioned in 2363. to defense.4 .TO BOLDLY GO WHERE NO ONE HAS GONE BEFORE. TO EXPLORE STRANGE. so do Starfleet's duties.

subspace flux.</P> <P>Ability to support up to 5.space exploration missions including charting and mapping. All units to be equipped with subspace driver accelerators. Minimum efficiency of 52% to be maintained through Warp 9.362 CURS 29 <H3>SPECIFICATIONS</H3><HR> <A NAME="PROP"><H4>PROPULSION</H4> <P>Sustainable cruise velocity of Warp Factor 9. Engine systems of choice to include but are not limited to at least two YPS 8063 fusion drive motors.200.6 for periods of up to twelve hours.</P> <P>Facilities to support Class M environmental range in all individual living quarters.2.92 lightspeed (c).0.000 cochrane-hours between neutron purge refurbishment. provisions for 10% of quarters to support Class H.</P> <A HREF="Index. first cultural contact scenarios. Reactor modules to be fieldreplaceable.</P> <P>Ability to support a wide range of mission-related ongoing research and other projects (including sufficient habitable volume and power generation for facilities and operations) without impact on primary mission operations. Multimode neutrino interferometry instrumentation. Life cycle of all primary coil elements to meet or exceed 1. and full biologic and ecologic studies.HTML">Go to home page</A><HR> <A NAME="ENVC"> <H4> ENVIRONMENT/CREW</H4> <P>Environmental systems to conform to Starfleet Regulatory Agency (SFRA).standard 102. Secondary (impulse) propulsion system to provide sublight velocities up to and including 0. and repair bays. K. or L environmental conditions. Life support modules to be replaceable at major starbase layover to permit vehiclewide adaptation to Class H. resupply. Independent impulse propulsion system of choice for primary hull to include but not be limited to YPS 8055 fusion drive motors.critical systems to be triply redundant. particle.000 m® for mission-adaptable facilities including living quarters for mission-specific attached personnel.</P> <A HREF="Index. Secondary coil elements to meet or exceed 2. Ability to support both on-board and probe-mounted science instrumentation. </P> <P>Space allocation for mission-specific facilities: Habitable area to include 800. Independent exploration mode capability of seven Standard years at nominal Warp 6 velocity for docked configuration.1.</P> .650 cochranes. Twometer diameter gamma ray telescope.02 x 10¦K. peak transitional surge reserve to exceed 4. warp field geometry to incorporate modified 55¡ Z-axis compression characteristics on forward warp lobe for increased peak transitional efficiency. Additional 2% of living quarters volume to be equipped for Class N and N(2) environmental adaptation. gravimetric. Wide-band life sciences analysis capability pursuant to Starfleet life contact policy directive. and quark population analysis sensor capability.HTML">Go to home page</A><HR> <A NAME="MISS"> <H4>MISSION</H4> <P> Ability to operate independent of starbase refurbishment for extended periods.</P> <P>Support facilities for auxiliary spacecraft and instrumented probes needed for short-range operations to include at least two independent launch.56:1 ratio of separation to maximum field strength. Warp nacelle center-lines to conform to 2. optical. Ability to maintain speeds of up to Warp 9. <P>Full spectrum EM. Warp driver coils efficiency to meet or exceed 88% at speeds up to Warp 7. K. Fifth-phase dilithium controlled matter/antimatter reactor primary power. Ability to execute deep. Upgradable experiment and sensor array design.000 cochrane-hours between neutron purge refurbishment. All life.19 for Class M compatible oxygen-breathing personnel.000.Sustainable field output to exceed 1. and L environmental conditions. field output not less than 180 millicochranes at 1.225% of nominal output (170 ns phase).000 non-crew personnel for missionrelated operations.

</P> <A HREF="Index. Subspace flux differential to be maintained within 0. All tactical shielding to have full redundancy.3(a) levels for EM and nuclear radiation. capitanul Picard a localizat-o in pagina sa de Web prin urmatorul URL: http://www. In acest caz fisierul tinta referit se specifica prin URL-ul acestuia. capable of warp flight and optimized for combat. with auxiliary system able to provide 65% of primary rating. structura acestora este mult mai clara.29. Fisierele de resurse referite intr-un document HTML nu trebuie sa se afle pe acelasi calculator cu acesta putand sa fie amplasate pe alte calculatoare server WWW.HTML">Go to home page</A><HR> </BODY> </HTML> Se observa ca acum.HTML Fig. assuming approximately five major shipwide system swapouts and upgrades at average intervals of twenty years.1MW maximum single emitter output. Two photon torpedo launchers required for battle section. aflata pe un server WWW al Guvernului.</P> <A HREF="Index.02 millicochranes. depending on specific mission requirements and hardware availability. cand informatia este distribuita in mai multe documente.PROGRAMARE IN JAVA .Note de curs 363 <P>All habitable volumes to be protected to SFRA-standard 347. one auxiliary launcher in primary hull. pe Tera. </P> <A HREF="Index.</P> <P> Ability to separate into two autonomous spacecraft comprising a battle section.HTML">Go to home page</A><HR> <A NAME="TACT"> <H4> TACTICAL</H4> <P>Defensive shielding systems to exceed 7.3 x 10° kW primary energy dissipation rate.HTML">Go to home page</A><HR> <A NAME="DSGN"> <H4>DESIGN LIFE</H4> <P>Spaceframe design life of approximately one hundred years. </P> <P>Tactical systems to include full array of Type X phaser bank elements on both primary and stardrive (battle) sections capable of 5. Minor refurbishment and upgrade to occur at approximately one-to five-year intervals.guv/DataBank.Fed. Such upgrades help insure the continuing usefulness of the ship even though significant advances in technology are anticipated during that time.4a . De exemplu pentru a prevedea o legatura cu banca de date a Federatiei. and a primary section capable of impulse flight and defensive operations</P> <P>Full independent sublight operational capability for command section in Separated Flight Mode.

4a si b rezultatul incarcarii acestei resurse de catre navigator. Listing 29.gif"></TD> <TD> <H3><B><I> WELCOME TO GALAXY CLASS STARSHIP. TO SEEK OUT NEW LIFE. Limbajul HTML permite gruparea a mai multor blocuri de text in liste formatate. and is currently under command of Captain JeanLuc Picard.HTML #DSGN"> DESIGN LIFE </A><HR> </BODY> </HTML> Liste Se observa ca in documentul Index.HTML">FEDERATION DATABANK </A><BR> <A HREF="MissionObj.4b In listingul 29.Home Page</TITLE> </HEAD> <BODY> <TABLE> <TR> <TD> <IMG SRC="StarTrek. AND NEW CIVILISATIONS.</I></B><H3></TD></TR> </TABLE><HR> <H5><B><I>Stardate 48030.HTML #ENVC"> ENVIRONMENT/CREW </A><BR> <A HREF=" Specs. It was comissioned in 2363.Fed. as well as in several crucial incidents defending the security of the <B>Federation</B>.<HR> <A HREF="http://www.HTML"> MISSION OBJECTIVES</A><BR> <A HREF="Specs. NEW WORLDS. este rational din punct de vedere structural sa grupam .html <HTML> <HEAD> <TITLE>USS Entreprise . NCC -1701-D</B>. Si in cazul documentului nostru.HTML #MISS"> MISSION</A><BR> <A HREF=" Specs.<BR> This latest starship is <B>Starfleet</B>‘s flagship and has already distingueshed in an impressive number of significant missions of exploration.4581</I></B><H5><HR> The <B>USS Entreprise.364 CURS 29 Fig.5 se vede cum a adaugat Picard referirea la aceasta resursa in Index.HTML #PROP"> PROPULSION</A><BR> <A HREF=" Specs.HTML apare o insiruire de legaturi la alte resurse.HTML #TACT"> TACTICAL </A><BR> <A HREF=" Specs.TO BOLDLY GO WHERE NO ONE HAS GONE BEFORE.USS Entreprise 1701-D.HTML iar in figura 29.guv/DataBank. TO EXPLORE STRANGE.HTML">SPECIFICATIONS</A><BR> <A HREF=" Specs.5 .29. is a Galaxy class starship built at the <B><I>Utopia Plannitia Fleet Yards</I></> above Mars.Index.

</LI>.5b Structura de definire a unei liste este: <TIP> <LI> element 1 </LI> <LI> element 2 </LI> …………………….29. cele ordonate cu marcajele <OL></OL>.5a Fig. Elementele listei se delimiteaza cu marcajele <LI>. . HTML asigura mai multe formate diferite pentru liste: • neordonate (marcate cu buline) • ordonate (numerotate secvential) • de tip director (cu elementele aliniate pe orizontala) • de tip meniu (simple fara buline sau numerotare) Listele neordonate se definesc cu marcajele <UL></UL>. Fig.</MENU>.</DIR> iar cele meniu cu <MENU>.29.Note de curs 365 legaturile din pagina Web intr-o astfel de lista.PROGRAMARE IN JAVA . cele director delimitate cu <DIR>.

HTML"> MISSION OBJECTIVES</A></LI> <LI><A HREF="Specs.</I></B><H3></TD></TR> </TABLE><HR> <H5><B><I>Stardate 48030.4581</I></B><H5><HR> The <B>USS Entreprise.OL. Listing 29.HTML #MISS"> MISSION</A></LI> <LI><A HREF=" Specs.6 .6 si figura 29.HTML #ENVC"> ENVIRONMENT/CREW </A></LI> <LI><A HREF=" Specs.gif"></TD> <TD> <H3><B><I> WELCOME TO GALAXY CLASS STARSHIP.HTML #PROP"> PROPULSION</A></LI> <LI><A HREF=" Specs.USS Entreprise 1701-D.<HR> <OL><!-.366 CURS 29 <LI> element n </LI> </TIP> unde TIP este unul din marcajele UL.HTML">SPECIFICATIONS</A></LI> </OL> <UL><!-.<BR> This latest starship is <B>Starfleet</B>‘s flagship and has already distingueshed in an impressive number of significant missions of exploration.-> <LI><A HREF=" Specs.6 este exemplificata utilizarea listelor ordonate si neordonate. It was comissioned in 2363.HTML #DSGN"> DESIGN LIFE </A></LI> </UL> <HR> </BODY> </HTML> . as well as in several crucial incidents defending the security of the <B>Federation</B>. and is currently under command of Captain JeanLuc Picard.DIR sau MENU.html <HTML> <HEAD> <TITLE>USS Entreprise . In listingul 29. AND NEW CIVILISATIONS.Lista ordonata .TO BOLDLY GO WHERE NO ONE HAS GONE BEFORE.List. NEW WORLDS.HTML">FEDERATION DATABANK </A></LI> <LI><A HREF="MissionObj. TO SEEK OUT NEW LIFE.HTML #TACT"> TACTICAL </A><BR></LI> <LI><A HREF=" Specs. Elementele listei sunt blocuri de text ce pot contine si marcaje HTML. TO EXPLORE STRANGE.Lista neordonata . NCC -1701-D</B>. is a Galaxy class starship built at the <B><I>Utopia Plannitia Fleet Yards</I></B> above Mars.-> <LI><A HREF="DataBank.Home Page</TITLE> </HEAD> <BODY> <TABLE> <TR> <TD> <IMG SRC="StarTrek.

• liste incuibate mixte ordonate/neordonate . TO EXPLORE STRANGE.Lista ordonata . It was comissioned in 2363.o lista ordonata ale carei elemente sunt liste neordonate.List. In listingul 29.<HR> <!-.-> <OL><!-. AND NEW CIVILISATIONS.7 si in figura 29.html <HTML> <HEAD> <TITLE>USS Entreprise .Lista mixta .6 Liste ordonate si neordonate Elementele listei pot sa fie tot liste rezultand astfel liste incuibate.4581</I></B><H5><HR> The <B>USS Entreprise.gif"></TD> <TD> <H3><B><I> WELCOME TO GALAXY CLASS STARSHIP. NEW WORLDS.PROGRAMARE IN JAVA .7 . as well as in several crucial incidents defending the security of the <B>Federation</B>.Note de curs 367 Fig.USS Entreprise 1701-D.</I></B><H3></TD></TR> </TABLE><HR> <H5><B><I>Stardate 48030.-> . Listing 29.TO BOLDLY GO WHERE NO ONE HAS GONE BEFORE. is a Galaxy class starship built at the <B><I>Utopia Plannitia Fleet Yards</I></> above Mars.29.<BR> This latest starship is <B>Starfleet</B>‘s flagship and has already distingueshed in an impressive number of significant missions of exploration.7 este prezentata utilizarea unei liste mixte. TO SEEK OUT NEW LIFE.o lista neordonata ale carei elemente sunt tot liste neordonate.Home Page</TITLE> </HEAD> <BODY> <TABLE> <TR> <TD> <IMG SRC="StarTrek. Variantele de combinatii utile sunt doua: • liste incuibate neordonate . and is currently under command of Captain JeanLuc Picard. NCC -1701-D</B>.

HTML #ENVC"> ENVIRONMENT/CREW </A></LI> <LI><A HREF=" Specs.USS Entreprise 1701D.HTML #PROP"> PROPULSION</A></LI> <LI><A HREF=" Specs.29.HTML #MISS"> MISSION</A></LI> <LI><A HREF=" Specs.</I></B><H3></TD></TR> </TABLE><HR> <H5><B><I>Stardate 48030. Listing 29.Lista neordonata .Home Page</TITLE> </HEAD> <BODY> <TABLE> <TR> <TD> <IMG SRC="StarTrek. is a Galaxy class starship built at the <B><I>Utopia Plannitia Fleet Yards</I></> above Mars.4581</I></B><H5><HR> The <B>USS Entreprise.HTML">FEDERATION DATABANK </A></LI> <LI><A HREF="MissionObj.gif"></TD> <TD> <H3><B><I>WELCOME TO GALAXY CLASS STARSHIP.HTML #TACT"> TACTICAL </A><BR></LI> <LI><A HREF=" Specs.TO BOLDLY GO WHERE NO ONE HAS GONE BEFORE. De exemplu primului element al meniului poate sa -i fie adaugata imaginea grafica a comunicatoarelor folosite de echipajul navei pentru a sugera comunicatia la distanta cu computerul Federatiei (listingul 29. NEW WORLDS.368 CURS 29 <LI><A HREF="DataBank.HTML">SPECIFICATIONS</A></LI> <UL><!-.7 Liste mixte In cadrul sau chiar locul textului acentuat dintr-o legatura.html <HTML> <HEAD> <TITLE>USS Entreprise . It was . TO EXPLORE STRANGE.HTML #DSGN"> DESIGN LIFE </A></LI> </UL></OL> <HR> </BODY> </HTML> Fig. AND NEW CIVILISATIONS. TO SEEK OUT NEW LIFE.ImageLink.8 . NCC -1701-D</B>.8).8 si figura 29. poate fi prevazuta o imagine care poate fi selectata cu mouse-ul.-> <LI><A HREF=" Specs.HTML"> MISSION OBJECTIVES</A></LI> <LI><A HREF="Specs.

pe randuri.<HR> <OL><LI> <A HREF="DataBank.HTML #TACT"> TACTICAL </A><BR></LI> <LI><A HREF=" Specs.Note de curs 369 comissioned in 2363.HTML #MISS"> MISSION</A></LI> <LI><A HREF=" Specs.gif”>FEDERATION DATABANK </A></LI> <LI><A HREF="MissionObj. Sub-ferestrele se pot si ele diviza la randul lor fiecare pe coloane sau randuri. etc.HTML #PROP"> PROPULSION</A></LI> <LI><A HREF=" Specs.PROGRAMARE IN JAVA . pe coloane. and is currently under command of Captain JeanLuc Picard. aparte sectiunea FRAMESET. in loc de sectiunea BODY din documentele HTML obisnuite.HTML #DSGN"> DESIGN LIFE </A></LI> </UL></OL> <HR> </BODY> </HTML> Fig. Aceasta sectiune este delimitata de perechea de marcaje <FRAMESET>. fie pe orizontala. Deci structura unui document HTML cu frame-uri este urmatoarea: <HTML> <HEAD> </HEAD> <FRAMESET> … definirea frame-urilor … </FRAMESET> </HTML> . In fiecare cadru astfel creat poate fi incarcat cate un document HTML distinct.</FRAMESET> care contine definirea subferestrelor sau frame-urilor.8 Imagini in hiprlegaturi Frame HTML permite (in cazul browserelor care accepta acest lucru) divizarea unei ferestre in sub-ferestre numite frame (cadru).<BR> This latest starship is <B>Starfleet</B>‘s flagship and has already distingueshed in an impressive number of significant missions of exploration. Divizarea se poate face fie pe verticala.HTML">SPECIFICATIONS</A></LI> <UL><LI><A HREF=" Specs.HTML #ENVC"> ENVIRONMENT/CREW </A></LI> <LI><A HREF=" Specs.HTML"> MISSION OBJECTIVES</A></LI> <LI><A HREF="Specs.29. as well as in several crucial incidents defending the security of the <B>Federation</B>. Un document cu frame-uri se aseamana foarte mult cu un document HTML obisnuit cu deosebirea ca dupa sectiunea HEAD.HTML"><IMG SRC=”sCom.

fiind interpretat ca o cerere de a dimensiona inaltimea frame-ului la tot spatiul ramas disponibil dupa amplasarea celorlalte frame-uri. Poate avea sase atribute: SRC. SCROLLING. Numarul n este optional. Daca valoarea este data in procente n% atunci randul va avea inaltimea reprezentand n din inaltimea totala a ferestrei. Daca un astfel de marcaj este introdus in sectiunea FRAMESET. • Atributul SRC are sintaxa: SRC=”url” . Acest marcaj defineste continutul frame-ului si modul sau de afisare. • Atributul ROWS stabileste divizarea ferestrei pe randuri.* ”.inaltimea primului frame va fi de 2/3 din inaltimea ferestrei iar a celui de al doilea 1/3. NAME. Daca nu exista in lista o inaltime scalata relativ. MARGINWIDTH. definind divizarea unui frame. De exemplu in cazul listei “ 2*. spatiul disponibil este impartit in mod egal la fiecare dintre ele.100) sau valori de scalare relativa. Marcajele FRAMESET pot fi incuibate intre alte marcaje FRAMESET. Daca inaltimea este specificata de o valoare urmata de caracterul * (n*) frame-ul respectiv va primi de n ori mai mult spatiu decat un frame avand inaltimea specificata numai cu caracterul . El are sintaxa: COLS="lista_de_latimi_ale_coloanelor" Lista_de_latimi_ale_coloanelor are aceiasi sintaxa ca si lista_de_inaltimi_ale_randurilor. Daca totalul inaltimilor randurilor este mai mic decat inaltimea ferestrei si exista in lista o inaltime scalata relativ. una din valorile din lista poate fi scalata relativ. Valorile sunt numere intregi reprezentand inaltimea in pixeli a randului sau procente (1. Marcajul <FRAME> este un marcaj vid(nu exista perechea </FRAME>). MARGINHEIGHT. Caracterul * are semnificatia frame_dimensionat_relativ. Deoarece suma inaltimilor randurilor trebuie sa fie egala cu inaltimea ferestrei browserului. Pentru fiecare frame definit de marcajul <FRAMESET>. in cadrul sectiuni FRAMESET respective trebuie sa apara marcajul <FRAME>. In cadrul sectiunii FRAMESET sunt permise alte marcaje FRAMESET incuibate precum si marcaje FRAME sau NOFRAMES.. • Atributul COLS stabileste divizarea ferestrei pe coloane. Astfel daca valoarea din lista este un numar intreg n atunci randul respectiv va avea inaltimea de n pixeli. Numarul de randuri este dat implicit de numarul de elemente ale listei. aceasta va fi dimensionata astfel incat totalul sa fie egal cu inaltimea ferestrei.370 CURS 29 Marcajul <FRAMESET> poate avea doua atribute – ROWS (randuri) si COLS(coloane). Dca exista in lista mai multe inaltimi scalate relativ. aceasta va fi ignorata de browser. El are sintaxa: ROWS="lista_de_inaltimi_ale_randurilor" Lista_de_inaltimi_ale_randurilor este o lista de valori separate prin virgula reprezentand inaltimea fiecarui rand la divizarea ferestrei. toate inaltimile vor fi scalate astfel incat suma lor sa dea 100%. Inaltimea randurilor scalate relativ se defineste sub forma n*. si NORESIZE. Un document cu frame-uri nu are sectiunea BODY si deci nu poate contine marcajele specifice acestei sectiuni.

Pentru a stabili fereastra tinta intr-o legatura aceasta trebuie specificata prin atributul TARGET al marcajului ancora <A>: <A HREF="url" TARGET="nume_fereastra">text_legatura</A> Cateva nume rezervate sunt predefinite de browser : • _blank – la selectarea unei legaturi. frame-ul va fi prevazut cu o bara de defilare. • Atributul NAME este folosit pentru a asocia un nume frame-ului astfel ca acesta sa poata fi accesat de legaturi din alte documente (de regula incarcate in alte frame-uri ale aceleiasi ferestre). Numele frameurilor se foloseste pentru a stabili frame-ul de destinatie in care se va incarca documentul specificat de o legatura.Note de curs 371 unde url specifica locatia resursei ce va fi afisata in frame. Aceasta valoare nu poate fi mai mica decat 1. Atributul NAME este optional. cu exceptia faptului ca el stbileste marginile superioara si inferioara ale frame-ului in timp ce MARGINWIDTH stabileste dimensiunea marginilor laterale. • _top – documentul cerut se incarca in fereastra principala indiferent de numarul de marcaje FRAMESET incuibate si de frame-ul din care s-a facut cererea • Atributul MARGINWIDTH este folosit pentru dimensionarea marginii frame-ului si are sintaxa MARGINWIDTH="n" unde n este latimea in pixeli. • _parent – documentul cerut se incarca in frame-ul parinte. • Atributul SCROLLING este folosit pentru a specifica trebuie sau nu prevazut cu o bara de defilare.PROGRAMARE IN JAVA . Sintaxa sa este: SCROLLING="yes|no|auto" Daca atributul primeste valoarea yes. documentul se incarca intr-o fereastra noua. • _self – la selectarea legaturii documentul se incarca in frame-ul in care se gaseste legatura. Daca . Implicit. Frame-urile fara atributul SRC sunt afisate fara continut. fara nume. Daca se specifica no. Devine _self daca fereastra nu are parinte. Sintaxa atributului NAME este: NAME="nume_fereastra" Numele trebuie sa inceapa cu un caracter alfanumeric sau caracterul “_”. Atributul este optional. frame-ul va fi prevazut cu o bara de defilare. toate ferestrele sunt fara nume. Atributul MARGINHEIGHT e asemanator ca sintaxa cu atributul MARGINWIDTH descris mai sus.

html. se observa ca fereastra a fost divizata in doua coloane. fiecare afisand un alt document (index.9 este prezentat un exemplu de pagina Web cu 3 frame-uri. In frame-ul din prima coloana s-a incarcat documentul index. browserul nu ii va permite utilizatorului sa redimensioneze frameul “tragand” cu mouse-ul de marginea acestuia. implicit frame-ul este redimensionabil.372 CURS 29 SCROLLING este setat pe auto. Atributul SCROLLING este optional. Daca nu este specificat.. header. Aceasta sectiune este ignorata de browserele capabile sa afiseze frame-uri.*"> <FRAME SRC="index_.html si info.9 Fereastra cu frame-uri Documentul HTML care a generat aceste trei frame-uri este cel din listingul 29.</NOFRAMES> delimiteaza textul HTML alternativ ce va fi afiosat de browserele care nu implementeaza mecanismul frame-urilor.html" NAME=2header SCROLLING="NO" MARGINHEIGHT=0 MARGINWIDTH=0 NORESIZE> <FRAME SRC="info.html" NAME=3info NORESIZE> </FRAMESET> </FRAMESET> .*"> <FRAME SRC="header. Fig.29.html iar in cel de jos documentul info.9 Listing 29. • Atributul NORESIZE nu primeste valoare.html" NAME=1index MARGINHEIGHT=0 MARGINWIDTH=0 SCROLLING="AUTO" FRAMEBORDER="YES" FRAMESPACING="1" NORESIZE> <FRAMESET ROWS="65.9 . Atributul este optional. In acest exemplu.html. browserul va afgisa bara de defilare numai daca este cazul.Frames. In randul de sus al celei de a doua coloane s-a incarcat documentul header.HTML <HTML> <HEAD> <TITLE>"Pagina Web cu frame-uri"</TITLE> </HEAD> <FRAMESET COLS="140. Coloana din dreapta a fost la randul ei divizata in doua randuri. valoarea implicita fiind auto.html. Marcajele <NOFRAMES> . Daca este specificat. Daca frame-ul adiacent are atributul NORESIZE specificat atunci nici marginea framului vecin nu poate fi deplasata.html). In figura 29.

HTML"><IMG SRC=”sCom.gif"></TD> <TD><H3><B><I>WELCOME TO GALAXY CLASS STARSHIP. NCC -1701-D</B>.HTML al carui continut este redat in listingul 29.<BR> This latest starship is <B>Starfleet</B>‘s flagship and has already distingueshed in an impressive number of significant missions of exploration. Listing 29.HTML <HTML> <HEAD> <TITLE> USS Entreprise . is a Galaxy class starship built at the <B><I>Utopia Plannitia Fleet Yards</I></> above Mars.10 .gif”>FEDERATION DATABANK </A></LI> <LI><A HREF="MissionObj.Home Page </TITLE> </HEAD> <FRAMESET ROWS="160. NEW WORLDS.HTML creat de capitanul Picard pentru a obtine o pagina Web cu framuri. It was comissioned in 2363.USS Entreprise 1701-D.TO BOLDLY GO WHERE NO ONE HAS GONE BEFORE.Note de curs <NOFRAMES> 373 <H2> Aceasta pagina se vede mai bine cu browserele Netscape sau InternetExplorer <H2> </NOFRAMES> </HTML> In listingul 29. and is currently under command of Captain JeanLuc Picard.<HR> <OL><LI> <A HREF="DataBank. .PROGRAMARE IN JAVA .HTML">SPECIFICATIONS</A></LI> <UL><LI><A HREF=" Specs.HTML #PROP"> PROPULSION</A></LI> <LI><A HREF=" Specs.html" NAME=Index SCROLLING="AUTO" NORESIZE> <FRAME SRC="info.HTML #DSGN"> DESIGN LIFE </A></LI> </UL></OL> <HR> </NOFRAMES> </HTML> In acest document HTML fereastra browserului este divizata in doua framuri orizontale Primul are o inaltime fixa de 160 de pixeli si incarca documentul din fisierul Header.MainPage.HTML #TACT"> TACTICAL </A><BR></LI> <LI><A HREF=" Specs.</I></B><H3></TD></TR> </TABLE><HR> <H5><B><I>Stardate 48030.4581</I></B><H5><HR> The <B>USS Entreprise.HTML #MISS"> MISSION</A></LI> <LI><A HREF=" Specs.html" NAME=Info SCROLLING="AUTO" NORESIZE> </FRAMESET> </FRAMESET> <NOFRAMES> <TABLE> <TR> <TD><IMG SRC="StarTrek.*"> <FRAME SRC="index1. AND NEW CIVILISATIONS.10 este prezentat fisierul MainPage.*"> <FRAME SRC="header.HTML"> MISSION OBJECTIVES</A></LI> <LI><A HREF="Specs. TO SEEK OUT NEW LIFE. as well as in several crucial incidents defending the security of the <B>Federation</B>.11. TO EXPLORE STRANGE.HTML #ENVC"> ENVIRONMENT/CREW </A></LI> <LI><A HREF=" Specs.html" SCROLLING="NO" NORESIZE> <FRAMESET cols="230.

TO EXPLORE STRANGE.12 – Index1.HTML din listingul 29.gif">FEDERATION DATABANK </A></LI> <LI><A HREF="Info. pagina . In el se incarca documentul din fisierul Info.10 este prezentata pagina Web afisata de browser la incarcarea documentului MainPage.Home Page introduction</TITLE> </HEAD> <BODY> <H5><B><I>Stardate 48030.Home Page header</TITLE> </HEAD> <BODY> <TABLE> <TR> <TD><IMG SRC="StarTrek.Home Page index1</TITLE> </HEAD> <BODY> <MENU> <LI><A HREF="DataBank. NCC -1701-D</B>.gif"></TD> <TD><H3><B><I>WELCOME TO GALAXY CLASS STARSHIP.HTML" TARGET="Index">SPECIFICATIONS</A></LI> </MENU> </BODY> </HTML> A doua coloana are o dimensiune scalata relativ si este prevazuta cu o bara de defilare daca este cazul.HTML" TARGET="Info"> MISSION OBJECTIVES</A></LI> <LI><A HREF="Index2.HTML <HTML> <HEAD> <TITLE> USS Entreprise . Daca browserul nu implementeaza framuri.<BR> This latest starship is <B>Starfleet</B>'s flagship and has already distingueshed in an impressive number of significant missions of exploration.19 – Header. as well as in several crucial incidents defending the security of the <B>Federation</B>.4581</I></B><H5><HR> The <B>USS Entreprise.html" TARGET="Info">INTRODUCTION</A> <LI><A HREF="MissionObj. AND NEW CIVILISATIONS.<HR> </BODY> </HTML> In figura 29.12 Listing 29.HTML" TARGET="_blank"><IMG SRC="sCom. TO SEEK OUT NEW LIFE.</I></B><H3></TD></TR> </TABLE> </BODY> </HTML> Al doilea frame orizontal este divizat la randul sau in doua coloane.13 – Info. and is currently under command of Captain JeanLuc Picard. In el se incarca documentul din fisierul Index1.HTML.HTML din listingul 29. NEW WORLDS.HTML <HTML> <HEAD> <TITLE> USS Entreprise .374 CURS 29 Listing 2.USS Entreprise 1701-D.TO BOLDLY GO WHERE NO ONE HAS GONE BEFORE.13 Listing 29. is a Galaxy class starship built at the <B><I>Utopia Plannitia Fleet Yards</I></> above Mars. Prima coloana are o latime fixa de 230 de pixeli si este prevazuta cu o bara de defilare daca este cazul. It was comissioned in 2363.HTML <HTML> <HEAD> <TITLE> USS Entreprise .

PROGRAMARE IN JAVA - Note de curs

375

afisata este identica cu cea din figura 29.8, textul din sectiunea NOFRAMES fiind identic cu cel din sectiunea BODY al fisierului ImageLink.HTML din listingul 2.16. Selectand din lista afisata optiunea FEDERATION DATABANK browserul va crea o fereastra noua (TARGET=”_blank”) in care va incarca fisierul afisand aceeasi pagina Web ca cea din figura 2.14b. Selectand optiunea SPECIFICATIONS in continutul frame-ului index va fi inlocuit cu cel specificat de fisierul Index2.HTML din listingul 2.22, incarcat in acest frame. Imaginea afisata va fi cea din figura 2.20.

Fig.29.10 Pgina cu frame-uri si legaturi
Listing 29.14 – Index2.HTML <HTML> <HEAD> <TITLE> USS Entreprise - Home Page index2</TITLE> </HEAD> <BODY> <MENU><LI><A HREF=" Specs.HTML #PROP" TARGET="Info"> PROPULSION</A></LI> <LI><A HREF=" Specs.HTML #MISS" TARGET="Info">MISSION</A></LI> <LI><A HREF=" Specs.HTML #ENVC" TARGET="Info">ENVIRONMENT</A></LI> <LI><A HREF=" Specs.HTML #TACT" TARGET="Info">TACTICAL </A><BR></LI><LI><A HREF=" Specs.HTML #DSGN" TARGET="Info">DESIGN LIFE</A></LI> <LI><A HREF=" Index1.HTML" TARGET="Index">BACK TO MAIN INDEX</A></LI> </MENU> </BODY> </HTML>

Selectand optiunea BACK TO MAIN INDEX se revine la continutul frame-ului index din figura 29.10 prin reincarcarea documentului Index1.HTML. Selectand legatura MISSION OBJECTIVES din indexul din figura 29.10 se incarca in frame-ul info documentul MissionObj.HTML. Selectand optiunea INTRODUCTION se reface continutul frame-ului Info prin incarcarea fisierului Info.HTML. In cazul din figura 29.11, selectand una din optiunile PROPULSION, MISSION, ENVIRONMENT, TACTICAL sau DESIGN LIFE in frame-ul Info se va incarca fisierul Specs.HTML, pozitionand la afisare portiunea de text corespunzatoare ancorei specificate de legatura.

376

CURS 29

Fig.29.11 Schimbarea continutului frame-ului index Astfel, selectand de exemplu optiunea MISSION, fereastra browserului va fi ce din figura 29.12. Textul din fereastra Info va fi pozitionat pe ancora <A NAME=”MISS”>.

Fig.29.12 Selectarea unei legaturi cu afisare in frame-ul Info

Formulare HTML
Formularele permit colectarea datelor de la utilizator ceea ofera posibilitatea de a asigura documentelor HTML un feedback, datele preluate putand fi transmise unor programe de pe calculatorul server HTTP pentru prelucrari diverse ( generare de comenzi, actualizarea unor baze de date, evaluare/testare de cunostinte, etc.). Marcajele folosite pentru realizarea formularelor sunt: <FORM> ... </FORM> - delimiteaza un formular in cadrul unui document HTML. <INPUT ...> ... </INPUT> - definesc un camp de editare. <OPTION> - defineste o optiune selectabila. <SELECT> ... <SELECT> - definesc un grup de optiuni selectabile <TEXTAREA ...> ... </TEXTAREA> - definesc un camp de editare pe mai multe randuri.

PROGRAMARE IN JAVA - Note de curs

377

In listingul 29.14 este prezentat un exemplu de folosire a acestor marcaje pentru realizarea unui chestionar. In figura 29.13 este aratata pagina de web afisata de browser la incarcarea fisierului Form.HTML care contine chestionarul.
Listing 29.14 – Form.HTML <HTML> <HEAD> <TITLE>Sample Questionnaire</TITLE> </HEAD> <BODY> <H3>Model Formular</H3> <P>Va rugam completati chestionarul urmator: </P> <FORM METHOD="GET" ACTION="http://www.host.org/sample.cgi"> <P>Nume: <INPUT NAME="nume" size="48"></P> <P>Studii: </P> <P>Superioare<INPUT NAME="studii" TYPE=RADIO VALUE="superioare"></P> <P>Medii <INPUT NAME="studii" TYPE=RADIO VALUE="medii"></P> <P>Vechime: <INPUT NAME="vechime" TYPE=text></P> <P>Limbi straine cunoscute: </P> <UL> <LI>Engleza <INPUT NAME="limbi" TYPE=checkbox VALUE="en"> <LI>Franceza <INPUT NAME="limbi" TYPE=checkbox VALUE="fr"> <LI>Germana <INPUT NAME="limbi" TYPE=checkbox VALUE="do"> <LI>Rusa <INPUT NAME="limbi" TYPE=checkbox VALUE=”ru"> <LI>Altele <TEXTAREA NAME="altele" cols=48 rows=4></textarea> </UL> Adresa: <INPUT NAME="adresa" SIZE="42"> <P>Va multumim ca ati completat acest chestionar.</P> <P><INPUT TYPE=SUBMIT> <INPUT TYPE=RESET></P> </FORM> </BODY> </HTML>

Fig.29.13 - model formular In acest exemplu marcajele de paragrafe <P>,<\P> si de liste <UL>,<\UL>,<LI><\LI> s-au folosit pentru amplasarea in pagina a elementelor formularului. Se observa ca elementele interactive ale formularului din exemplul nostru sunt butoane cu interblocare (radio button) folosite la introducerea informatiei privind

378

CURS 29

studiile, casete de validare (check box) folosite pentru specificarea limbilor straine cunoscute, casete de editare pe un rand folosite pentru specificarea vechimii sau pe mai multe randuri folosite pentru specificarea altor limbi straine in afara celor explicitate in formular. De asemenea formularul contine doua butoane inscriptionate “Submit” “si Reset”. Actionarea butonului "Submit” are ca efect expedierea datelor inscrise in formular iar apasarea butonului “Reset” duce la stergerea informatiilor introduse si reluarea editarii formularului. • marcajele <FORM>,</FORM> Aceste marcaje delimiteaza textul de definire al formularului de colectare de la utilizator a datelor. Atributele marcajului <FORM> specifica unde, cum si sub ce forma sa fie expediate datele colectate. ¾ · atributul ACTION este un URL care specifica locatia unde va fi expediata informatia inscrisa in formular pentru a fi prelucrata si se va obtine raspunsul. daca atributul ACTION este omis, atunci implicit se considera URL-ul documentului care contine formularul. ¾ · atributul METHOD selecteaza protocolul folosit la transmiterea informatiei. In cazul in care atributul ACTION specifica un URL HTTP, protocoalele de transmitere a datelor din formular pot fi GET sau POST. In cazul in care atributul METHOD nu este specificat, protocolul implicit este GET. Daca METHOD=”GET” atunci datele codificate sub forma unui sir de interogare (query string)se adauga la URL -ul specificat de ACTION. De exemplu daca ACTION=”http://www.host.org/procesare.pl”, atunci la apasarea butonului “Submit”, browserul va acesa locatia http://www.host.org/procesare.plsir_de_interogare “procesare.pl” este numele unui program aflat pe calculatorul server HTTP care va prelucra sirul de interogare primit ca parametru. Serverul HTTP separa locatia programului de sirul de interogare, lanseaza programul “procesare.pl” si ii transmite sirul de interogare ca parametru. Daca METHOD=”POST”, sirul de interogare este expediat de browser catre serverul HTTP intr-un bloc de date separat de URL-ul care contine cererea de prelucrare. Sirul de interogare contine informatia introdusa de utilizator in formular, codata cu ajutorul unor caractere speciale de separare. aceste caractere speciale sunt caracterul Spatiu, Procent(%), semnul intrebarii (?), ampersand (&), egal (=) si plus(+). Revenind la exemplu nostru se vede ca formularul este de fapt o grupare de “controale”. Fiecare control are asociat la definire un nume. Dupa completarea formularului, fiecarui control ii este atribuita o “valoare” constind din textul introdus de utilizator in cazul casetelor de editare sau in textul setat la definirea controlului in document in cazul casetelor de validare si abutoanelor interblocate. Codificarea informatiilor inscrise in formular se face astfel: 1. datele se grupeaza in perechi nume=valoare. In cazul casetelor de validare si a butoanelor interblocate se iau in considerare numai controalele validate de utilizator. Spatiile din textul valorii sunt inlocuite cu semnul +. O serie de caractere care nu au voie sa apara in sirul de interogare fiind rezervate se inlocuesc cu valoarea lor codata in HEX si prefixata de semnul Procent(%) conform tabelului 29.1. 2. perechile nume=valoare se separa inter ele prin caracterul &. 3. sirul astfel obtinut se prefixeaza cu semnul ?. Tabel 29.1

PROGRAMARE IN JAVA - Note de curs
Caracter Tab “ ( ) , . ; Cod %09 %22 %28 %29 %2C %2E %3B Caracter : < > [ \ ] ^ Cod %3A %3C %3E %5B %5C %5D %5E Caracter ‘ { | } ~ + CR,LF

379
Cod %60 %7B %7C %7D %7E %2B %0D%0A

Astfel in cazul exemplului din figura 29.13, browserul va transmite sirul de interogare cu cererea de acces:
http://www.host.org/sample.cgi?nume=BigCrash&studii=superioare&vechim e=20&limbi=en&limbi=fr&limbi=ru&altele=C%0D%0AC%2B%2B%0D%0AJava%0D%0A Pascal%0D%0ABasic&adresa=Starbase+3%2C+Level+23

• marcajele <INPUT>,</INPUT > Marcajul <INPUT> defineste un control Input reprezentand un camp al carui continut poate fi editat de utilizator. Atributele elementului Input sunt: ¾ ALIGN stabileste alinierea pe verticala a imaginii controlului. Se foloseste numai in combinatie cu atributul TYPE=IMAGE ¾ CHECKED Arata ca o caseta de validare sau un buton interblocat se afiseaza validat. ¾ MAXLENGTH Indica numarul maxim de caractere ce pot fi intrioduse intr-o caseta de editare text. Acest numar poate fi mai mare decat latimea casetei specificata cu atributul SIZE. Daca textul introdus este mai lung decat spatiul vizibil stabilit de SIZE, textul din campul de editare va fi defilat corespunzator. Daca MAXLENGTH este omis, numarul implicit de caractere este nelimitat ¾ NAME Stabileste numele folosit la codificarea informatiei inscrise in sirul de interogare. Symbolic name used when transferring the form's contents. ¾ SIZE Specifica in functie de tipul controlului dimensiunea sau precizia campului de editare. De exemplu pentru a defini o caseta de editare cu latimea de 24 de caractere se specifica INPUT TYPE=text SIZE="24". ¾ SRC Specifica un URL ce refera un fisier imagine. Se foloseste numai cu TYPE=IMAGE. ¾ TYPE Defineste tipul de date acceptate de control. Implicit este text. Mai multe tipuri de controale pot fi definite cu acest atribut: ‰ CHECKBOX : folosit pentru casete de validare. Daca o astfel de caseta este validata, numele ei este inscris in sirul de interogare imperecheat cu valoarea specificata cu atributul VALUE. Pot fi definite mai multe controale de acest tip, avand acelasi nume. Toate controalele validate vor genera perechi nume/valoare ce se vor inscrie in sirul de interogare. Daca atributul VALUE este omis, valoarea implicita este “on”

380
‰

CURS 29

HIDDEN : controlul nu este vizibil pentru utilizator dar valoarea continuta este inscrisa in sirul de interogare. Aceasta valoare poate fi folosita pentru a transmite informatii privind interactiunea client-server. ‰ IMAGE : Un control imagine pe care utilizatorul sa il poata clicai cu mouse-ul determinand expedierea imediata a formularului. Coordonatele punctului de pe imagine selectat de utilizator sunt inscrise in sirul de interogare sub forma a doua prechi nume/valoare, una pentru coordonata x, numele fiind nume_control.x si cealalta pentru y, numele fiind nume_control.y. Coordonatele sunt masurate in pixeli relativ la coltul din stanga sus al imaginii. Fisierul care contine imaginea este specificat cu atributul SRC. ‰ PASSWORD: este identic cu atributul TEXT cu exceptia faptului ca sirul de caractere introdus de utilizator nu este vizibil. ‰ RADIO: este folosit pentru butoane interblocate. Mai multe astfel de controale avand acelasi nume formeaza un grup.Utilizatorul nu poate selecta decat unul din controalele grupului. Numai valoarea butonul selectat este imperecheata cu numele si adaugata sirului de interogare. Valoarea acestor controale trebuie specificata explicit cu atributul VALUE. ‰ RESET: este butonul care daca este apasat restaureaza formularul setand toate controalele cu valorile implicite. Eticheta implicita de pe buton este Reset si poate fi modificata cu atributul VALUE. Daca butonului i s-a asociat un nume cu atributul NAME, la expedierea formularului, perechea nume/valoare este adaugata sirului de interogare. ‰ SUBMIT: este butonul care apasat, determina expedierea formularului. Eticheta implicita de pe buton este dependenta de browser si poate fi modificata cu atributul VALUE. Daca butonului i s-a asociat un nume cu atributul NAME, la expedierea formularului, perechea nume/valoare este adaugata sirului de interogare. ‰ TEXT: este o caseta de editare text pe un singur rand. Se foloseste impreuna cu atributele SIZE si MAXLENGTH. ‰ TEXTAREA: este o o caseta de editare text pe mai multe randuri. Se foloseste impreuna cu atributele SIZE si MAXLENGTH. ¾ VALUE: Valoarea initiala afisata de controalele text sau starea la casetele de validare si butoanele interblocate. • marcajele <SELECT>,</SELECT > si <OPTION>,</OPTION> Aceste marcaje delimiteaza o lista de optiuni din care utilizatorul poate selecta unul sau mai multe elemente. Elementele listei sunt etichete text delimitate de marcaje le <OPTION>, </OPTION>. Atributele marcajului <SELECT> sunt: ¾ MULTIPLE: Pentru a permite selectarea a mai multor elemente din lista, in marcajul <SELECT> trebuie specificat atributul MULTIPLE: <SELECT MULTIPLE>. Controlul afisat de browser va fi o lista tip MENU sau MENU DERULANT daca numarul de elemente ale listei este mai mare decat cel de elemente vizibile specificatcu atributul SIZE. ¾ NAME: specifica numele ce va intra in perechea nume/valoare inscrisa in sirul de interogare. ¾ SIZE: specifica numarul de elemente vizibile ale listei. Daca este 1, controlul afisat de browser va fi o lista tip caseta de selectie. Exemplude folosire a marcajului select:

Valoarea asociata elementului selectat este implicit chiar textul etichetei delimitat de marcajele <OPTION>. elementul selectat implicit este primul element din lista. In caz contrar. .Note de curs <SELECT NAME="aroma"> <OPTION>Vanilie</OPTION> <OPTION>Capsuni</OPTION> <OPTION>Rom</OPTION> <OPTION>Piersica</OPTION> </SELECT> 381 Elementul implicit se specifica cu atributul SELECTED in marcajul <OPTION>.PROGRAMARE IN JAVA .</OPTION> . Aceasta valoare poate fi stabilita si explicit cu atributul VALUE putand fi diferita in acest caz de textul etichetei elementului.

Scrierea script-urilor este cam acelasi lucru cu programarea cu exceptia faptului ca limbajul de comanda este adeseori mult mai simplu si mai usor de invatat decat un limbaj de programare.bat este un exemplu de script. una cate una. choice /c:abc Selectati o optiune if errorlevel 3 goto MSBAckup if errorlevel 2 goto MSAv if errorlevel 1 goto Edit :Edit edit goto End :MSAv msav goto End :MSBackup msbackup goto End :End Fisierul de comenzi start. .BAT (de la Batch file) Comenzile din fisier vor fi citite interpretate si executate pe rand.1 este prezentat un exemplu al unui astfel de fisier de comenzi care afiseaza un meniu.1 . El adauga setului de comenzi DOS o noua comanda (comanda start) cu functionaliate complexa pe care producatorul sistemului de operare nu a prevazut-o si nici nu putea sa o prevada. Dar a prevazut sistemul cu facilitatea ca utilizatorul sa-si poata construi dupa plac propriile comenzi care sa-i satisfaca cerintele. Un script nu este altceva decat o succesiune de comenzi (numite instructiuni) pe care programul le parcurge una cate una executand ceea ce scriptul ii cre sa faca.PROGRAMARE IN JAVA . si in functie de optiunea utilizatorului lanseaza in executie un program sau altul. de catre interpretorul de comenzi command. Pentru a-si face programele mai flexibile ei le prevad cu facilitatea ca utilizatorul sa le poata extinde sau modifica functionalitatea prin intermediul unor script-uri scrise chiar de el ca in cazul exemplului de mai sus.bat @echo off cls echo. echo A Microsoft Editor echo B Microsoft Anti-Virus echo C Microsoft Backup echo. Producatorii de software se straduiesc din rasputeri sa raspunda cerintelor utilizatorilor dar nu pot anticipa totul. Este imposibil pentru un program sa satisfaca toate exigentele ale tuturor utilizatorilor.Note de curs 383 Curs 30 JavaScript Sub MS DOS daca vrem sa automatizam o serie de operatii vom edita un fisier de comenzi cu extensia . Listing 30.start.com In listingul 30.

posibilitatile oferite de HTML sunt limitate. Aceste comenzi se prezinta sub forma unor instructiuni scrise intr-un limbaj botezat de Netscape LiveScript in prima sa versiune iar mai tarziu JavaScript. Compania Netscape Comunications si-a inzestrat browserele cu un interpretor al unor comenzi mai complexe decat cele HTML. in contextul acestei carti. Din punctul nostru de vedere..Atunci cand este cazul. fiind destinat celor care doresc sa adauge paginilor lor de Web elemente interactive fara a fi programatori avansati. Acest fisier are extensia . JavaScript va fi o punte ce va va netezi trecerea de la HTML la programarea in Java. browserul interpreteaza si executa una cate una instructiunile scriptului delimitat de aceste marcaje.384 CURS 30 Un script este deci o succesiune de instructiuni date unui program.js”> … </SCRIPT> Java se incadreaza intre marcajele .compania care a elaborat limbajul Java.</SCRIPT> avand sintaxa: <SCRIPT LANGUAGE=”JavaScript”> … codul JavaScript … </SCRIPT> este necesara mentiunea LANGUAGE=”JavaScript” deoarece unele browsere accepta scripturi scrise si in alte limbaje decat JavaScript. produs de SUN Microsystems. Marcajul <SCRIPT> Intr-un document HTML.host. Instructiunile scrise in acest limbaj sunt grupate in cadrul unui document HTML intre perechea de marcaje <SCRIPT>.JS ca in exemplul urmator: <SCRIPT SRC=”http://www. mai precis numai Netscape Navigator produs Netscape Comunications de si Internet Explorer produs de Microsoft si integrat in sistemul de operare Windows 95 prevad acest mecanism. marcajele fiind niste comenzi date browserului cum sa afiseze blocul de text pe care il delimiteaza sau ce alta resursa sa incarce ca raspuns la selectarea de catre utilizator a unei hiperlegaturi. Totusi. De exemplu chiar browserul HotJava.ul unui fisier script”> ………….</SCRIPT> constituind un asa numit script. Din acest punct de vedere si documentele HTML sunt niste script-uri.0 sau mai mare accepta si sintaxa: <SCRIPT SRC=”URL . Browserul Netscape cu versiunea 3. Limbajul JavaScript este destinat scrierii unor aplicatii simple. statisticile arata ca 90% din utilizatori folosesc pe calculatoarele lor fie Netscape Navigator fie Internet Explorer. un script <SCRIPT>.com/program. pe care acesta le interpreteaza si le executa. Asa cum am vazut. </SCRIPT> Fisierul script referit in marcaj prin URL contine codul scriptuli Java ce va fi incarcat de browser si executat. nu interpreteaza scripturile JavaScript. Nu toate browserele au implementat interpretorul de script-uri JavaScript. Pentru a le imbunatati functionalitatea.

HTML <HTML> <HEAD> <TITLE> JavaScript Hallo World </TITLE> </HEAD> <BODY> <H1>Primul program JavaScript va saluta:</H1> <HR> <SCRIPT LANGUAGE="JavaScript"> <!-window.30. programul se termina.status="Hallo World!".30.2 . • dupa apasarea butonului.1 b afisarea documentului HTML In acest exemplu scriptul Java face urmatoarele: • inscrie in bara de stare a ferestrei sirul de caractere “Hallo World!”. Listing 30. window. • creaza o fereastra cu mesajul “Uitativa in bara de stare!” si un buton de confirmare.Note de curs 385 In listingul 30. //--> </SCRIPT> </BODY></HTML> Fig.PROGRAMARE IN JAVA .HalloWorld.1b rezultatul incarcarii si executiei acestuia de catre browser.1a si 30.1 a executia scriptului Java Fig.alert("Uitati-va in bara de stare !"). • astepta apasarea butonului. .2 este prezentat un prim exemplu de introducere a unui script Java intrun document HTML iar in figura 30.

c){ … instructiuni JavaScript ale functiei func1 … } function func2(x.</SCRIPT> in cadrul documentului. function funcN(u. Scripturile Java pot fi amplasate oriunde in document.386 CURS 30 Se observa ca desi documentul HTML a fost incarcat (titlul sau apare in bara de titlu a ferestrei si scriptul Java se executa )el nu a fost afisat pana cind nu s-a terminat executia scriptului.5.3.w in cazul lui funcN) ca si cand ar fi un fel de mini-programe.c in cazul functiei func1 sau x.2.w){ … instructiuni JavaScript ale functiei funcN … } </SCRIPT> </HEAD> <BODY> … corpul documentului HTML … </BODY> • Functiiile trebuiesc definite inainte sa fie apelate. y=5 si y=7) Conditia ca acest mecanism sa functioneze este ca definitia functiei sa se gaseasca in documentul HTML inainte de sectiunea in care se produce apelul ei ca in exemplul din listimngul 30. Apelul functiei se face prin numele acesteia transmitandu-I-se si argumente concrete pe care ea sa le prelucreze(de exemplu func2(3.z.z){ … instructiuni JavaScript ale functiei func2 … } ………………………………………………. si z ale caror valori sunt initializate cu valorile specificate la apelul functiei.y. Rezultatul executiei acestui script este redat in figura 30.HTML <HTML> <HEAD> <TITLE> Welcome to Java Land </TITLE> <SCRIPT LANGUAGE=”JavaScript”> <!— . Listing 30.b. In urma apelului. in alte sectiuni ale codului JavaScript din document. Functiile sunt sectiuni de cod JavaScript care realizeaza la executie o anumita prelucrare a datelor transmise ca argument (a.b.. atunci cand este nevoie de o astfel de procesare a unor date. Putem sa folosim oricate perechi de marcaje <SCRIPT>.7) este un apel la functia func2. respectiv x=3. func2 incepe sa fie executata de browser prelucrand argumentele x. y.3 – JavaLand.cu urmatoarele observatii: • Definitiile de functii JavaScript (vom vedea mai tarziu ce sunt astea) se plaseaza obligatoriu in antetul documentului: <HTML> <HEAD> <TITLE> Pagina Web cu functii JavaScript</TITLE> <SCRIPT LANGUAGE=”JavaScript”> function func1(a.v. Ulterior.v. in cazul lui func2 sau u. se apeleaza la serviciile functiei corespunzatoare.y.

Note de curs function bunVenit(unde){ document. • Scripturile Java este bine sa fie incadrate intre marcajele HTML de comentarii <!—si -. Fig.2 Apelul functiilor • Tot codul JavaScript.HTML afisat de un browser JavaScript Un browser non-JavaScript ar afisa insa in ferseastra sa ceva in genul textului din figura 30.PROGRAMARE IN JAVA .4.4 – BunVenit. }//--> </SCRIPT> </HEAD> <BODY><HR> <SCRIPT LANGUAGE=”JavaScript”> <!—Ascunde scriptul de browserele non-Java bunVenit(“in Java Land”).3.HTML <HTML> <HEAD> <TITLE> Bun venit </TITLE> <SCRIPT LANGUAGE=”JavaScript”> function bunVenit(unde){ document.30. trebuie sa il transcriem in toate paginile.write(“<H1>Bine ati venit”+unde+”!<H1>”).> pentru ca sa nu fie afisate ca simplu text de browserele non-JavaScript ca in cazul documentului din listingul 30.4 Listing 30. fara a interpreta programul nostru. } </SCRIPT> </HEAD> <BODY><HR> <SCRIPT LANGUAGE=”JavaScript”> bunVenit(“la noi”). Daca vrem sa folosim acelasi cod si in alte pagini.3 Documentul BunVenit. . inclusiv definitiile functiilor exista si sunt vizibile numai in cadrul paginii in care sunt prevazute.// Apelul functiei cu argumentul actual //--> </SCRIPT><HR> </BODY> 387 Fig. </SCRIPT> <HR> </BODY> Un browser JavaScript va afisa in fereastra sa textul generat de functia bunVenit ca in cazul din figura 30.write(“<H1>Bine ati venit”+unde+”!<H1>”).30.

. unele avand o structura simpla. Setarea. luminozitatea (0. Obiecte In viata de zi cu zi suntem obisnuiti sa avem de a face cu diferite obiecte. Combinatia // desemneaza un comentariu in limbajul JavaScript. etc. masini...// JavaScript }//. altele destul de complexe.100%). ton sonor (0.HTML afisat de un browser non-JavaScript Pentru a face invizibil codul JavaScript pentru browserele non-JavaScript. are o serie de caracteristici.30.5 – Bun_Venit. volum sonor(0. Listingul 3.388 CURS 30 Fig..5 exemplifica cum se ascunde codul scriptului pentru a nu fi afisat de browserele non-JavaScript. avioane. sa luam ca obiect de referinta un televizor. cum ar fi diferite echipamente electronice. saturatia de culoare (0. cum ar fi starea (pornit/standby).> ar fi semnalata ca eroare deoarece nu face parte din limbaj si nu este “inteleasa” de interpretor. Ele sunt intotdeauna interpretate ( executate ) dupa ce browserul a incarcat tot documentul dar inainte ca acesta sa fie afisat in fereastra.HTML <HTML> <HEAD> <TITLE> Welcome to Java Land </TITLE> <SCRIPT LANGUAGE=”JavaScript”> <!—Ascunde scriptul de browserele non-Java function bunVenit(unde){ document.>.// JavaScript ( apelul functiei bunVenit) //--> </SCRIPT><HR> </BODY> • Nu conteaza unde sunt amplasate instructiunile scriptului in documentul HTML. interpretorul ignorand textul ce ii urmeaza pana la capatul randului. acestor proprietati nu .100%). 40 de canale avand fiecare asociata o frecventa de receptie.. In caz contrar.4 Documentul BunVenit. combinatia de caractere -. o sa le numim proprietati. Acest obiect cand este in functiune.100%). marcajul -. contrastul (0. Pe de alta parte.-> </SCRIPT> </HEAD> <BODY><HR> <SCRIPT LANGUAGE=”JavaScript”> <!—Ascunde scriptul de browserele non-Java bunVenit(“ la noi”). Listing 30.100%).100%). el trebuie incadrat de marcajele de comentariu <!—si -.> trebuie precedat de doua caractere “slash” (//) pentru a fi ignorat de interpretorul JavaScript al browserului ce executa codul.write(“<H1>Bine ati venit”+unde+”!<H1>”).

etc.5 – Joc electronic Jocul este de fapt o cutie despre continutul careia nu stim nimic. Apasarea tastelor de comanda determina cutia neagra sa initieze actiuni al caror rezultat consta in modificarea proprietatilor obiectelor virtuale reprezentate pe ecran. genereaza o imagine reprezentand pe ecran niste obiecte virtuale. Actionand asupra tastelor telecomenzii sau asupra butoanelor de reglaj.30. omul interpreteaza imaginea de pe ecran a navei spatiale ca pe un obiect asemanator celor din lumea reala – doar ca acest obiect evolueaza (isi modifica proprietatile) in spatele ecranului. directia si viteza de deplasare. Iata un alt exemplu – un joc electronic ca cel din figura 30. etc. utilizatorul nu trebuie sa cunoasca schema de principiu si de montaj a televizorului si sa fie un priceput electronist pentru a-l putea folosi. avand si ele proprietati ca si obiectele reale: coordonatele fiecarei nave. trage un proiectil. Datorita imaginatiei cu care este inzestrat. intr-o lume virtuala. Aceasta cutie conectata la un televizor. gradul de distrugere. Proprietatile acestor obiecte virtuale se modifica actionand asupra comenzilor: accelereaza. cantitatea de combustibil in rezervoarele acestora.5. realimenteaza cu combustibil. pe care utilizatorul o tine strins si o butoneaza cu frenezie. Fig. ca si cand ar fi o jucarie reala. munitia disponibila. ore intregi. schimba directia. Este drept ca acest obiect nu este intrutotul virtual fiind conectat la lumea reala printr-o interfata reala. . palpabila. Avind la dispozitie acest mecanism.PROGRAMARE IN JAVA . Aceasta nu il impiedica pe utilizator sa foloseasca comenzile pentru a manevra obiectul in fel si chip.Note de curs 389 se face umbland cu surubelnita si letconul in maruntaiele sale (desi acest lucru este posibil. nu este recomandabil). franeaza. putem activa niste functii interne ale televizorului care actioneaza asupra proprietatilor modificandu-le la valorile dorite. de exemplu doua nave cosmice. o asa numita cutie neagra prevazuta cu o interfata cu butoane de comanda. Pentru aceasta televizorul nostru este prevazut cu telecomanda sau cu butoane de reglaj.

Acum insa partenerul de joc este chiar calculatorul. Utilizatorul conduce avionul virtual de pe ecran cu ajutorul unui joystick similar cu mansa unui avion de vanatoare. Pana aici lucrurile stau asemanator cu cazul precedent. Acest dispozitiv este interfata avionului virtual OV1 cu utilizatorul.6 Legatura dintre lumea reala si obiectul virtual prin interfeta In mod asemanator. Sa analizam cazul unui joc pe calculator care simuleaza o batalie aeriana.7. Fig. Dar cine conduce atunci avioanele inamice? In cazul precedent conducea partenerul de joc. programatorul lucreaza cu obiecte virtuale asemanatoare celor prezentate. mai precis un program manager al obiectelor virtuale.6 este reprezentata schematic aceasta legatura intre obiectul virtual si lumea reala prin intermediul interfetei. Pentru celalalte obiecte virtuale ( avioane. .30. Relatia utilizator – manager obiecte virtuale este reprezentata schematic in figura 30. in programarea orientata obiect.390 CURS 30 In figura 30. De fapt managerul este cel care prin intermediul driverului de interfata cu joystick-ul preia comenzile date de jucator le interpreteaza si le retransmite avionului virtual pilotat de acesta. rachete lansate)el elaboreaza singur comenzi pe baza unor strategii de joc prin care simuleaza comportamentul unor piloti inamici in cazul avioanelor sau sistemele de ghidarea automata in cazul rachetelor.

pentru realizarea unor module hardware ca in figura 30. Putem reprezenta schematic acest obiect ca in figura 30. Intr-adevar. Fig. metodologia programarii orientate pe obiecte foloseste obiecte abstracte software. Asa cum icebergul are sub apa cea mai mare parte din volumul sau. Acesta este la randul sau un obiect ale carui detalii de realizare sunt ascunse utilizatorului.7 Obiecte virtuale conduse de program Aceasta figura ne sugereaza mai curand o schema de conexiuni hardware decat o schema logica uzitata candva la proiectarea software-ului procedural. un obiect software care incapsuleaza laolalta datele privind proprietatile si logica de comanda a actiunilor de modificare a acestora. este prevazut cu o interfata (butoane.Note de curs 391 Fig. telecomanda) pin intermediul careia comunica cu utilizatorul . definite de programator pe care le asambleaza impreuna pentru a realiza un obiect abstract mai complex.30. fiind inchis (incapsulat) intr-o carcasa sigilata. cum ar fi un calculator sau un televizor. Modulele la randul lor intra in componenta unui sistem mai complex.9.8 Interconectarea a doua microchip-uri intr-in modul hardware Un obiect virtual. si obiectul virtual are in spate.30. este asemanator cu varful unui iceberg. .PROGRAMARE IN JAVA . cum ar fi imaginea unui avion pe ecranul computerului.8. invizibil. exact la fel cum in proiectarea hardware se folosesc circuitele integrate (tot un fel de cutii nergre – nu trebuie sa le cunoastem schema pentru a le folosi – prevazute cu o interfata pentru aplicarea semnalelor de intrare).Pentru a putea fi folosit.

codul JavaScript are dreptul sa-si afiseze propriile . In programarea obiect stricta. prin apel la metodele publice ale obiectului (pot exista si metode private ce pot fi solicitate numai de alte metode ale obiectului . Fereastra Browserului Ferestrele afisate de browserele HTML sunt obiecte avand proprietati si metode publice. Actiunile de care este capabil obiectul se numesc metode asa cum datele sale interne se numesc proprietati. • Proprietatea status In partea de jos a ferestrei se afla bara de stare in care browserul afiseaza diferite mesaje care de regula il informeaza pe utilizator asupra desfasurarii procesului de incarcare a documentului HTML solicitat (vezi figura 30.10). Modificarea lor din exteriorul obiectului este permisa numai indirect. obiectul fereastra este desemnata prin numele window. Ca proprietar al ferestrei in care este afisat documentul in care este incorporat.30.9 Obiectul software si obiectul virtual Evolutia pe ecran a avionului virtual este rezultatul afisarii imaginii sale in urma modificarii proprietatilor obiectului software (cum ar fi coordonatele ecran) prin executarea unei actiuni comandate prin interfata de catre un modul exterior.392 CURS 30 Fig. In codul JavaScript. Fereastra afisata de browser poate fi comandat prin instructiuni JavaScript incluse in documentul HTML incarcat in sensul modificarii proprietatilor si apelarii metodelor oferite de obiectul fereastra. Sa analizam intai care sunt proprietatile obiectului window. Un astfel de mesaj este de exemplu Document Done inscris de browser in bara de stare pentru a semnala ca a terminat de incarcat si afisat o pagina Web. proprietatile obiectului nu pot fi modificate direct din exterior (se spune ca sunt proprietati private ale obiectului).publice sau private – dar nu pot fi apelate din exterior).

Folosind informatia din proprietatea opener. Din aceasta fereastra utilizatorul poate selectind din meniul File optiunea NewWindow (vezi figura 30. etc. Proprietatea opener a unei ferestre date contine o referinta la fereastra parinte a acesteia.status = “mesajul JavaScript trebuie inscris intre ghilimele” . • Proprietatea opener La lansarea in executie.status = “Salutari. Ca urmare a atribuirii de mai sus textul mesajului (fara ghilimelele ce il incadreaza in instructiune ) va aparea in bara de stare a ferestrei.11 – Deschiderea unei noi ferestre Din fiecare fereastra la randul sau se pot deschide alte ferestre. Fig. Pentru aceasta nu are decat sa seteze proprietatea status a obiectului window astfel ca aceasta sa contina sirul de caractere al mesajului.PROGRAMARE IN JAVA . Fiecare intrare in tablou este o referinta la un frame descendent al unui FRAMESET parinte. De . in fiecare putand sa fie afisata o alta pagina de Web. De exemplu un script java dintr-o fereastra copil poate afisa un mesaj in bara de titlu a ferestrei parinte cu instructiunea : window.opener.11) sa deschida alte noi ferestre.Note de curs 393 Fig. browserul deschide pe ecran o prima fereastra. identice cu prima. Asa cum vom vedea mai departe o fereastra noua poate fi deschisa si prin program apeland metoda open. un script java executat de aceasta noua fereastra poate accesa proprietatile si metodele ferestrei parinte. batrane!” . Sintaxa instructiunii care realizeaza aceasta operatie este: window.30.30.10 – fereastra browserului si bara de stare mesaje in bara de stare. • Proprietatatile frames Aceasta proprietate este un tablou de referinte la frame-urile ferestrei.

Daca se apasa Butonul OK. metoda intoarce valoarea booleana true (adevarat) iar daca se apasa pe Reset.13. Prin intermediul referintei la frame aceste proprietati si metode pot fi accesate de un script Java. Astfel apelurile self. OK si Reset-.30. .fed”).status(“Hallo!”) si window. Metoda afiseaza in aceasta fereastra textul mesajului si asteapta apasarea unuia dintre butoane.alert(“Datele introduse sunt incorecte”).394 CURS 30 exemplu daca fereastra este divizata in dou frame-uri.length are valoarea 1).frames[I].length care contine indexul in tablou al ultimului frame(in cazul exemplului nostru frames. Metoda afiseaza textul transmis ca argument si asteapta ca utilizatorul sa dea un clic pe buton confirmand ca a citit mesajul. Apelul metodei se face cu: window.12. Fig.proprietate_sau_metoda_obiect_frame Proprietatile si metodele obiectelor frame vor fi discutate ulterior.starfleet.status(“Hallo!”) vor sunt echivalente.confirm(“Ati introdus adresa de e-mail picard@uss1701D. • Obiectul self Referinta self este un sinonim al referintei window prin care un script Java se poate referi la obiectul fereastra in cadrul careia se executa. • Metoda alert( ) Apelul la aceasta metoda a obiectului fereastra determina afisarea unei ferestere de mesaj de avertizare. Browserul va afisa pe ecran fereastra din figura 30. Vom discuta in continuare metodele obiectului fereastra. prevazuta cu un buton OK.12 Fereastra de avertizare generata de metoda alert • Metoda confirm( ) Aceasta metoda afiseaza un alt tip de fereastra de mesaj prevazuta cu doua butoane. Accesul la o proprietate sau o metoda a frame-ului prin referinta din tabloul frames se face cu apelul: Window. primul este referit de frames[0] si al doilea de frames[1]. Numarul de frame-uri al ferestrei se poate obtine din proprietatea frames. Astfel in urma executiei instructiunii JavaScript: window. Frame-urile sunt si ele obiecte cu proprietatile si metodele lor.atunci intoarce valoarea booleana false (fals). Fereastra de confirmare afisata de browser este redata in figura 30.

Utilizatorul poate edita textul implicit din campul de editare dupa care apasa pe unul din butoane.14.fed ca in figura 30.OK si Reset-.“”.confirm("Ati introdus adresa de e-mail "+adress).starfleet. Metoda afiseaza in fereastra prompt mesajul si initializeaza campul de editare cu textul implicit dupa care asteapta apasarea pe unul din butoane. window. sirul intors este vid .prompt("Ce adresa de e-mail aveti?".PROGRAMARE IN JAVA .13 Fereastra de confirmare generata de metoda confirm • Metoda prompt ( ) Aceasta metoda afiseaza o fereastra prevazuta cu un camp de editare in care utilizatorul poate tasta un sir de caractere si cu doua butoane . Daca apasa butonul Reset-."picard@uss1701D.”text implicit in campul de editare”).prompt</H1> <HR> <SCRIPT LANGUAGE="JavaScript"> <!-- var adress=window.prompt() </TITLE> </HEAD> <BODY> <H1>window. nu contine nici un caracter.30.HTML <HTML> <HEAD> <TITLE> JavaScript window.Prompt.strafleet.6 browserul va afisa fereastra prompt din figura 30.15.6 .fed"). Incarcand de exemplu documentul din listingul 30. Listing 30.fed sa apara worf@uss1701D.Note de curs 395 Fig. //--> </SCRIPT> </BODY></HTML> Fig. Daca apasa pe OK metoda va returna sirul de caractere introdus de utilizator.14 Fereastra prompt Se editeaza textul din campul de editare astfel incat in locul adresei de e-mail picard@uss1701D.starfleet. .prompt(“mesaj de afisat in fereastra”. Metoda este apelata cu: window.30.

Incarcand acest document.fereastra de confirmare afisata va fi cea din figura 30.17 rezultatul apasarii pe butonul Reset • Metodele focus( ) si blur( ) Metoda focus seteaza fereastra ca tinta a intrarilor de la tastatura.396 CURS 30 Fig.16.7.18. Un alt mod de a realiza acelasi efect este apelul la metoda blur aferestrei curente.15 Editarea textului din campul de editare Daca se apasa pe butonul OK browserul va afisa fereastra de confirmare din figura 30. browserul va afisa imaginea din figura 30. Fig.17.30.blur( ) • Metoda scroll( ) Fie documentul HTML din listingul 30.opener)apeland la metode focus a acesteia.opener. Fig. .30. activeaza fereastra parinte a ferestrei curente (window.De exemplu instructiunea window.30. Aceasta metoda comuta de pe fereastra curenta pe fereastra parinte a acesteia: window.focus( ).16 rezultatul apasarii pe butonul OK Daca se apasa pe butonul Reset.

Pentru a vedea o alta portiune a imaginii aceasta trebuie “defilata” la coordonate noi.7 .scroll(0.opener: window. 0) ale imaginii.18 Imaginea din fisierul Orbit1. va face ca fereastra curenta sa arate pagina Web incarcata incepand cu coltul din stanga sus. Coltul din stanga sus al ferestrei este plasat la coordonatele (0. Utilizatorul se poate folosi pentru aceasta de barele de defilare verticala si orizontala cu care este prevazuta fereastra. Aceasta metoda permite defilarea ferestrei la un punct de coordonate (x. In figura 30.162).opener.Note de curs Listing 30.150).HTML <HTML> <HEAD> <TITLE> Orbit </TITLE> </HEAD> <BODY> <IMG SRC=”orbit1.30.jpg”> </BODY> </HTML> 397 Se observa ca imaginea este mai mare decat spatiul ferestrei si deci este vizibila numai partial.scroll(0.19 este reprezentat efectul instructiunii window. Astfel de exemplu instructiunea window. Fereastra curenta poate determina defilarea imaginii in fereastra parinte prin referinta window.0).Orbit1.scroll(122. Fig.y) in pixeli.PROGRAMARE IN JAVA . Ca referinta este luat coltul din stanga sus al ferestrei care are coordonatele (0.jpg incarcata in fereastra browserului Defilarea se poate face si din document printr-o instructiune JavaScript care apeleaza metoda scroll ( ) a ferestrei. • Metodele open( ) si close( ) .162) constand in defilarea imaginii la coordonatele (122.0).

specifica daca bara de stare sa fie vizibila sau nu. Cand aceasta metoda este apelata fereastra curenta (in care se executa scriptul Java ramane pe loc si o noua fereastra este deschisa pe ecran. care poate fi folosit pentru referirea ulterioara a acesteia. Sintaxa instructiunii de apel a acestei metode este: window.”caracteristica1. unde url desmneaza locatia resursei ce trebuie incarcata in noua fereastra. • resizable=yes/no .19 Defilarea imaginii cu metoda scroll( ) Elementele acestei liste pot fi: • toolbar = yes/no . asociat ferestrei. caracteristica2. • copyhistory = yes/no specifica daca noua fereastra sa fie mosteneasca de la fereastra parinte lista ultimelor pagini accesate in cursul sesiunii curente (istoricul). • directories = yes/no . • status = yes/no . • scrollbars=yes/no .”nume_fereastra”. nume_fereastra. .Lista de caracteristici caracteristica1. butoane de navigatie.specifica daca bara de menu sa fie vizibila sau nu.open(“url”.30.specifica daca bara de butoane standard Back/Forward/Home sa fie vizibila sau nu. ….specifica daca butoanele din categoria What’s New si What’s Cool. titlul.specifica daca barele de defilare sa fie vizibile sau nu.specifica daca campul de inscriere a locatiei sa fie sau nu vizibil. • menubar=yes/no .398 CURS 30 Metoda open( ) permite o noua fereastra a browserului.specifica daca noua fereastra poate sau nu sa fie redimensionata de utilizator.”). • location = yes/no . numele intern. Fig. caracteristica2. etc.… contine specificatii privind atributele ferestrei nou deschise cum ar fi dimensiunea.

close( ).specifica inaltimea in pixeli a noii ferestre. Astfel daca browserul incarca documentul href.HTML <HTML> <HEAD> <TITLE> location href() </TITLE> </HEAD> <BODY> <H1>utilizare location.ro/document.server. Sintaxa instructiunii de apel este: window.8 .20 – Obiectul “location” • Proprietatea location.html al carui continut este redat in listingul 30.href</H1> <SCRIPT LANGUAGE="JavaScript"> <!-location.8 va intalni in cadrul acestuia instructiunea JavaScript location.html" Odata inscrisa noua locatie.pixeli .7 .HTML . Locatia In fereastra afisata de browser apare o caseta de editare unde utilizatorul poate sa inscrie URL-ul resursei Web pe care vrea sa o incarce (figura 30.Href.html din listingul 30.20).html".href="http://www. //--> </SCRIPT> </BODY> </HTML> Listing 30. Executia aceastei instructiuni il va determina sa incarce documentul location.ro/document.org/mydir/location.nexus3.8.href Aceasta proprietate contine sirul de caractere al URL-ului resursei accesate de browser.specifica latimea in pixeli a noii ferestre.Note de curs • • 399 width = nr. Fereastra afisata de browser este cea din figura 30. browserul va incarca documentul specificat in fereastra curenta. Astfel pentru a determina browserul sa incarce documentul avand URL-ul http://www.org/mydir/location.Location. Metoda close( ) determina atunci cand este apelata inchiderea ferestrei.nexus3.href=" http://www.pixeli .html. afisandu-l in fereastra imediat ce a terminat de afisat href. un script Java il va memora in proprietatea href a obiectului locatie: location.21. height = nr.href="http://www.server. Listing 3.PROGRAMARE IN JAVA . Figura 30.html.html". Aceasta caseta este si ea un obiectavand numele location.

ro" Browserul se conecteaza la serverul HTTP prin accesarea unui port "ascultat" de acesta. proprietatea host contine doar subsirul subliniat care desemneaza calculatorul gazda pentru serverul HTTP: http:// http://www."nume_fereastra".server.org/mydir/location.href="http://www.href. ….html ¾ location.open( ) a ferestrei curente: window. • Proprietatea location.org/MYDIR/location.nexus3. De exemplu daca serverul "asculta" pe portul 6001.Courier New" SIZE=3 COLOR="#ff0000"> <P>location. caracteristica2. Sunt insa servere HTTP configurate sa "asculte" pe alte numere de port decat cel implicit."”caracteristica1. Astfel in cazul URL -ului din exemplul precedent. URL-ul va fi: http://www.400 CURS 30 <HTML> <HEAD> <TITLE>OBIECTUL "location"</TITLE> </HEAD> <BODY LINK="#0000ff" VLINK="#800080"> <FONT SIZE=6><P>OBIECTUL "<I>location</I>"</P> </FONT><P>Aceasta pagina a fost incarcata in urma executiei unei</P> <P>instructiuni JavaScript:</P> <FONT FACE="Courier.ro:6001/document.location. Valoarea implicita a numarului de port pentru protocolul HTTP este 80. Pentru ca browserul sa poata comunica cu un astfel de server in URL trebuie inclusa si specificarea portului de conectare.html Odata incarcat documentul location.open(location.host contine sirul de caractere "http://www.server. scriptul Java poate folosi location. Pentru a crea o fereastra noua in care sa fie incarcat si afisat documentul dat.html".21 .</P> </BODY> </HTML> Figura 30.”).host Aceasta proprietate contine doar o parte din sirul de caractere al URL-ului paginii curente afisate de browser si anume cea care localizeaza calculatorul gazda.html. incercati sa apasati butonul "Back" din bara de butoane a browserului si incercati sa explicati ce se intampla.href la apelul metodei window.nexus3.html .

• Proprietatea location. de exemplu o cale spre un alt document HTML.host contine sirul de caractere "6001".nexus3.html#ancora ¾ location.org:6001/mydir/location. location.org:6001".html ¾ location.port si location.hash contine sirul de caractere "ancora ".nexus3.org/mydir/ altele/document.org/mydir/ altele/document.pathname = "/mydir/altele/document. Atribuind o valoare noua acestei proprietati.Note de curs 401 iar proprietatea location.host contine sirul de caractere "http:// www.host contine sirul de caractere "http:// www.hash Atunci cand in URL este specificat nu numai documentul ce se incarca ci si o referire la o ancora din cadrul acestuia marcata cu <A NAME="nume_ancora">.pathname contine sirul de caractere "/mydir/location. Astfel instructiunea JavaScript: location. aceasta proprietate contine numele ancorei respective.nexus3. location.html ". prima locatia calculatorului gazda al serverului HTTP a doua numarul portului pe care "asculta" acesta si ultima subsirul care specifica protocolul folosit la conectare.hostname. Daca in URL nu este specificat un numar de port.nexus3.org:6001/mydir/location.protocol Aceste trei proprietati contin. ¾ location.nexus3.search . ¾ location.org:6001".html". browserul va accesa serverul pentru a incarca noul document.html ¾ location. http:// http://www. Astfel in cazul cand URL-ul este: http://www.nexus3.host si location. va determina browserul sa incarce documentul document.hostname au acelasi continut iar location.host va include si portiunea cu numarul portului a URL -ului curent: http://www. • Proprietatea location.PROGRAMARE IN JAVA . • Proprietatea location.html aflat in subdirectorul altele din directorul mydir.protocol contine sirul de caractere "http:".pathname Aceasta proprietate contine parte din sirul de caractere al URL-ului paginii curente afisate de browser care specifica calea spre documentul accesat in sistemul de fisiere al calculatorul gazda: http:// http://www.org:6001/mydir/location.html ¾ location.html cu URL-ul http://www. • Proprietatile location.port contine un sir vid de caractere ("").nexus3.

Proprietatile obiectului history sunt history.back( ). Metodele obiectului history permit navigarea spre documaentele ale caror URL-uri sunt inscrise in lista istoricului navigatiei.search contine tocmai aceasta componenta din URL.go(deplasament) determina accesarea URL-ului aflat la deplasament-ul transmis ca argument.6 ISTORICUL NAVIGATIEI Browserele tin istoricul navigatiei de la un document la altul intr-un obiect numit hystory. Astfel metoda history. browserul emite o cerere catre serverul HTTP de a executa un program specificat de URL-ul transmis.afisat in fereastra browserului .22 este prezentata fereastra history la browserul Netscape Navigator iar in figura 3.back() si history.forward() Aceste doua metode au efecte similare apasarii butoanelor Back si respectiv Forward din bara de butoane a browserului.nexus3. utilizatorul apasa pe butonul submit.go(-1) este echivalenta cu history. Astfel in cazul exemplului din figura 30. inapoi (back).Istoricul navigatiei la browserul Netscape Navigator .href) si history. argumentul poate sa fie si un sir de caractere.22 acest numar este 4 iar in cazul celui din figura 30. 3.search contine sirul "DateFormular". • metodele history.23 folder-ul history al lui Internet Explorer.30. URL-ul contine pe langa adresa programului si un sir de interogare pe care serverul il va pasa ca parametru programului la serviciile caruia a apelat browserul. Browserul va cauta intrarea in lista in care se regaseste partial sirul de caractere transmis ca Fig. In cea de a doua varianta. permitind navigarea inapoi in pagina precedenta si respectiv inainte la pagina care a fost parasita cu Back. relativ la pozitia curenta in lista.22 .current care contine URL-ul documentului curent .length care contine lungimea actuala a listei de pagini Web vizitate (numarul de elemente ale listei).forward( ) iar history.402 CURS 30 Am vazut in capitolul precedent ca atunci cand intr-o pagina Web care contine un formular. Argumentul deplasament poate avea valori pozitive sau negative. Acest istoric este tinut sub forma unei liste de URL-uri ale paginilor vizitate.(avand deci acelasi continut cu location. In figura 3.org/mydir/program?DateFormular ¾ location.go(sub_sir) Aceste doua metode permit saltul la URL-ul unui element arbitrar din lista istoricului navigatiei. Astfel in cazul cand URL-ul este: http://www.23 este 3.go(1) este echivalenta cu history. Daca este pozitiv. Proprietatea location. De exemplu instructiunea: history. • metodele history.go(deplasament_lista) si history. navigarea se face inainte (forward) iar daca este pozitiv.

Combinatia de doua cifre HEX gg reprezinta ponderea componentei de culoare verde iar ponderea componentei albastre. Celalalte culori se obtin prin combinarea culorilor de baza cu ponderi diferite.. Astfel daca specificam culoarea prin combinatiia #000000 fondul pe care va fi afisat documentul este de culoare neagra (0 rosu.html avand URL-ul http://www. Este posibila stabilirea unei culori a fondului pe care este afisat documentul.org/mydir/href. Obiectul Document Documentul incarcat de browser este si el tratat ca un obiect avand proprietati si metode. De exemplu pentru lista din figura 3. Aceasta se face cu atributul BGCOLOR (de la BackGroundColor)al marcajului <BODY>: <BODY BGCOLOR="# rrggbb "> ….30. Deoarece nu se cunoaste dinnainte ce posibilitati de a afisa culori are calculatorul pe care va fi incarcat si vizualizat documentul.23 . verde(green) si albastru(blue). verde si albastru sunt la maxim si deci culoarea rezultata este alb. Restul combinatiilor le afiseaza sub forma unei texturi care sugereaza culoarea care ar trebui sa rezulte in realitate.go("href.bgColor si dogument. Valorile pentru aceasta componenta pot fi cuprinse deci intre 00 si FF ( in zecimal asta corespunde domeniului 0…255). Culoarea fundalului se codifica prin combinatia rrggbb unde rr reprezinta ponderea componentei de culoare rosie exprimata cu doua cifre in baza 16 (HEX).html aflat in lista la pozitia 2.Textul documentului…. textul si imaginile documentului erau afisate pe un fondul gri al ferestrei browserului. browserul prelucreaza codul culorii afisand numai 16 culori solide.Istoricul navigatiei la browserul Internet Explorer argument si va accesa documentul respectiv.Note de curs 403 Fig.22 apelul history. pentru ca acesta sa fie vazut la fel si pe un calculator care poate afisa doar 16 culori si pe unul care afiseaza 16 milioane de culori.24. Daca combinatia este #FFFFFF asta inseamna ca componentele de rosu.fgColor In exemplele discutate pana acum.html") va determina accesul la documentul href. Numele atribuit de browser paginii Web curente este document. • proprietatile document. 0 verde si 0 albastru).PROGRAMARE IN JAVA .nexus3. </BODY> In sistemul RGB culorile de baza sunt rosu(red). . Astfel de exemplu combinatia #FFD700 corespunde unei culori de fond aurii dar nu are corespondent in cele 16 culori solide posibile si atunci est afisata de browser sub forma unei o texturi ca cea din figura 30.

Browserul pastreaza informatia privind legaturile deja vizitate un numar de zile prestabilit dupa care le readuce la starea de legaturi nevizitate.bgColor si poate fi modificata printr-o instructiune JavaScript care atribuie acesteia o alta valoare decat cea initial continuta de aceasta.24 .25 Fig. • proprietatile document. De exemplu instructiunea document. Odata afisate in pagina. Astfel atribuirea: document.404 CURS 30 Fig.Textul documentului…. Se poate specifica o alta culoare tot in cadrul marcajului <BODY> prin atributul TEXT: <BODY TEXT="# rrggbb "> ….BGCOLOR="#FFD700" Culoarea fondului documentului este continuta de proprietatea document. </BODY> unde combinatia rrggbb specifica culoarea textului obisnuit din document.linkColor Pe lunga textul obisnuit. Ea poate fi modificata prin program prin atribuirea unei alte valori diferite de cea originala.document.alinkColor.bgColor = "#008080" determina ca culoarea de fond a documentului sa devina cea din figura 30.fgColor="#FFFFFF" va face ca textul sa fie afisat cu culoarea alba (trebuie sa fim atenti la alegerea culorii de fond pentru ca textul sa fie vizibil). document. ¾ legatura activata(selectata).30.fgColor (de la ForeGroundColor) are valoarea setata de acest atribut al marcajului <BODY>. chiar si atunci . starea legaturii este evidentiata printr-o culoare distincta a textului accentuat. in document se afla si texte incadrate de marcaje de legatura de tipul <A HREF="referinta" >text accentuat</A> In pagina afisata. textul accentuat apare evidentiat prin subliniere si culoare distincta de cea a textului obisnuit. Aceasta implicit este culoarea neagra. Proprietatea document.. Pentru ca utilizatorul sa distinga usor legaturile deja vizitate de cele pe care urmeaza eventual sa le viziteze si sa vada si ce legatura tocmai a activat.25 .30.vlinkColor si document.bgColor="#008080" O alta caracteristica a documentului este culoarea de afisare a textului obisnuit din document. ¾ legatura deja vizitata. Astfel. legaturile se pot gasi in trei stari: ¾ legatura neselectata.

in ordinea in care acestea au fost inscrise in textul documentului. "Joi". Textul afisat in bara de titlu a ferestrei poate fi schimbat prin atribuirea unei noi valori acestei proprietati: document."Vineri". Culoarea celor trei tipuri de legaturi este stabilita implicit de browser dar poate fi stabilita si prin atributele LINK.anchors este un tablou continand valorile (numele) tuturor "ancorelor" din pagina.</TITLE> incadreaza un text ce reprezinta titlul documentului si este afisat de browser in bara de titlu a ferestrei. marcajul <A NAME="nume_ancora"> amplaseaza in textul acestuia o "ancora" ce poate fi referita intr-o legatura din alt document sau din documentul curent.anchors[0] document.Note de curs 405 cand revine la pagina respectiva dupa o perioada mai lunga de timp. document. in sectiunea BODY.anchors[6] Fiecare din elementele de mai sus contine numele unei ancore din textul documentului. accesul la elementele tabloului se face prin intermediul unui index care specifica numarului de ordine al ancorei: document. in sectiunea HEAD. Proprietatile document. Astfel atribuirile: document. a celor vizitate pe rosu si a celei activate pe verde. • proprietatea document. document. Astfel daca in document au fost definite in ordine ancorele cu numele "Luni". utilizatorul va sti ce legaturi a vizitat la accesarile anterioare."Duminica" aceste siruri de . document.title Intr-un document HTML. VLINK si ALINK ale marcajului <BODY>: <BODY LINK="#rrggbb" VLINK="#rrggbb" ALINK="#rrggbb"> ….alinkColor="#00FF00".linkColor="#00FFFF".Textul documentului…. </BODY> Atributul LINK stabileste culoarea pentru legaturile nevizitate.anchors Am vazut in capitolul precedent ca intr-un document HTML.PROGRAMARE IN JAVA . Culoarea legaturilor poate fi modificata prin program prin atribuirea unei alte valori diferite de cea originala. VLINK=purple."Sambata".vlinkColor si document.title = "Noul titlu al paginii Web" • proprietatea document.. Proprietatea document. VLINK pentru cele vizitate si ALINK pentru legatura activata.title.linkColor."Miercuri". Sirul de caractere al titlului este accesibil intr-un script Java prin proprietatea document.anchors[1] ……………………. document.alinkColor au valoarile setata de aceste atribute ale marcajului <BODY>. va seta culoarea legaturilor nevizitate pe galben. and ALINK=red."Marti".. Culorile implicite sunt : LINK=blue.vlinkColor="#FF0000". marcajele <TITLE>.

in ordinea in care acestea apar in document. document. • proprietatile document. … . Desi este posibil sa modificam prin atribuire valorile inscrise in tabloul document.lastModified Aceasta proprietate contine un sir de caractere care specifica data calendaristica a ultimei modificari aduse documentului curent. links [1] …………………….nexus3. prin atribuirea: document. numarul de ancore in textul documentului curent este dat de document. iar numarul de elemente din tablou este dat de proprietatea acestuia document. ele nu vor mai fi valide. daca nu sunt actualizate corespunzator modificarilor in document. In cazul nostru. • proprietatea document.nexus3.org/". • proprietatea document.URL = "http://www. Aceasta informatie poate fi folosita pentru a tine o evidenta statistica a locurilor din care a fost accesata pagina.Images si document.URL Aceasta proprietate poate fi folosita pentru a determina browserul sa incarce in locul paginii curente un alt document.</IMG>) si respectiv appleturile Java (definite . aceste proprietati sunt tablouri continand referinte la formularele (definite cu marcajele <FORM>. Tablourile in limbajul JavaScript sunt si ele obiecte (pe care le vom discuta in capitolul ulterior).length. document. Daca aceste referinte sunt facute chiar in documentul curent.referrer Daca pagina curenta a fost incarcata prin selectarea unei legaturi dintr-o alta pagina.links[3] = "http://www.</FORM>). Un script poate folosi aceasta informatie pentru a arata utilizatorului cat de "proaspata" este informatia continuta de pagina Web curenta. Valorile intrarilor din tablou pot fi modificate prin atribuire ca in exemplul de mai jos: document.length.links.html". • proprietatea document.anchors[6].anchors[2]. • proprietatea document.anchors acest lucru nu are sens deoarece ancorele joaca doar rolul de puncte de legatura pentru referinte din alte documente sau din documentul curent. Accesul la elementele tabloului se face printr-un index: document. document. imaginile (definite cu marcajele <IMG SRC=>.Forms.406 CURS 30 caractere sunt continute si de elementele tabloului document.links[0] document. Astfel numarul de elemente din tablou este continut de proprietatea length a acestuia.org/alta_pagina.anchors..anchors.links Aceasta proprietate este similara cu cea precedenta cu deosebirea ca document. aceasta proprietate contine URL-ul paginii din care s-a facut referinta.Applets Ca si in cazul ancorelor si legaturilor.links este un tablou ce contine toate legaturile specificate cu marcajul <A HREF="legatura">.anchors[0].

ignorate in mod normal.write("<H2>Utilizarea metodei <I>write</I></H2>").</APPLET>) din documentul curent. pe parcursul capitolelor urmatoare. TAB. Aceasta caracteristica a functiei writeln este utila numai in cazul in care se afiseaza text preformatat incadrat de marcajele <PRE>. metoda writeln adauga la sfarsitul sirului de caractere afisat un terminator de linie new_line (linie noua) de altfel ignorat de browser (daca chiar se doreste trecerea la o linie noua. obiectului document are si trei metode ce pot fi apelate de un script Java. Listing 30. Amanunte despre aceste elemente ale documentului HTML vor fi discutate la momentul potrivit. Diferenta dintre write si writeln consta in faptul ca dupa afisarea textului.</PRE>. In acest caz browserul ia in consideratie la afisare si caracterele de formatare ASCII .9 .write( ) si document.26. Pe langa proprietati.26 .write() .write("<H1>Hallo World!</H1>"). De exemplu daca dorim sa afisam in fereastra textul in format HTML <H1>Hallo World!</H1> instructiunea JavaScript folosita va fi: • document. • metoda document. Ca parametru aceste metode primesc un sir de caractere continand textul in format HTML pe care dorim sa il afisam in fereastra. se va inscrie la sfarsitul sirului de caractere marcajul HTML <BR> ). In listingul 30.write()</TITLE> </HEAD> <BODY> <SCRIPT LANGUAGE="JavaScript"> <!-document. Imaginea obtinuta este redata in figura 30.PROGRAMARE IN JAVA .HTML <HTML> <HEAD> <TITLE>document.write( ) pentru afisarea in fereastra browserului. Aceasta operatie nu afecteaza continutul documentul curent sau a variabilelor si proprietatilor obiectelor.metoda document.SPACE. LINE_FEED si CARRIAGE_RETURN.9 este prezentata utilizarea metodei document.3.clear( ) Aceasta metoda sterge continutul ferestrei curente. //--> </SCRIPT> </BODY> </HTML> Fig.write. • metodele document.Note de curs 407 cu marcajele <APPLET CODE=>.writeln( ) Aceaste doua metode permit afisare de text HTML in fereastra curenta. Este o operatie pur cosmetica care doar sterge imaginea afisata in fereastra browserului pregatind locul pentru ca o noua afisare de informatii sa nu se suprapuna peste imaginea anterioara.

Apasarea de catre utilizator a unui astfel de buton declanseaza automat executia functiei JavaScript asociate. lungimea sa (numarul de elemente pe care le cuprinde) este data de proprietatea length. Obiectele Buton Pe langa butoanele Sumbit si Reset in cadrul unui formular pot fi definite si alte butoane fara o functionalitate precisa.forms[i]. Componentele formularului pot fi acesate prin referintele continute de tabloul elements. ele sunt referite de proprietatea forms a obiectului document.elements.) inscrise in ordinea definirii lor in formular. de validare.method Aceasta proprietate contine metoda de transfer a sirului de interogare a serverului stabilita cu atributul METHOD din marcajul <FORM>. • proprietatea document. a doua de elements[1] si asa mai departe. Numarul de elemente ale tabloului este dat de proprietatea length a acestuia. Am vazut in capitolul precedent ca metodele posibile sunt doua: GET si POST. Astfel atribuirea document. butoane.method="get". forms[0] este referinta la primul formular din tabloul forms (proprietate a obiectului document). Asa cum am vazut.action="Alt_URL".forms[i].408 CURS 30 Obiectele Formular Formularele definite intr-un document cu marcajele <FORM>. etc. • proprietatea document.forms[0]. Astfel prima componenta este referita de elements[0].forms[i]. iar elements este proprietatea obiectului formular referit de forms[0]. Metoda stabilita de marcajul <FORM METHOD=…> poate fi modificata prin atribuirea unei noi valori proprietatii method ca in exemplul urmator: document.forms[0]. Acesta fiind la randul sau un tablou.elements Proprietatea elements reprezinta un tablou ale carui elemente sunt referinte la componentele formularului (casete de editare.</FORM> sunt la randul lor obiecte.forms[0]. Aceasta atribuire stabileste pentru primul formular din document metoda de transfer GET. • proprietatea document. De exemplu numarul componente ale primul formular din document este dat de document.length unde document este documentul curent. In cadrul formularului un astfel de buton se defineste tot prin marcajul <INPUT>: <INPUT TYPE="button" NAME="nume_control" VALUE="eticheta" onClick="functia_asociata()"> . Accesul la un obiect formular se face prin intermediul referintei document. Unui astfel de buton i se poate asocia o functie JavaScript. Valoarea ei poate fi modificata prin atribuirea unei noi valori sub forma unui sir de caractere. In continuare sunt discutate proprietatile obiectelor formular astfel refrerite. modifica proprietatea action a primului formular din document.forms[i] unde i este numarul de ordine al formularului in document.action Aceasta proprietate contine URL-ul programului apelat pentru prelucrarea sirului de interogare obtinut dupa completarea de catre utilizator a formularului si apasarea butonului Submit.

PROGRAMARE IN JAVA .elements[0]. care emuleaza apasarea butonului de catre utilizator.forms[i]. Proprietatile unui control de tip button sunt numele acestuia name si valoarea (eticheta inscrisa pe suprafata butonului) value si tipul acestuia type. Apelul prin referinta.type ("button").length are valoarea 1 ) si deci are indexul i=0 iar butonul este primul si singurul control din formular (document.Button. . Proprietatile nume valoare si tip ale controlului sunt accesibile prin referintele document.forms[0].elements[0]. la aceasta metoda are un efect similar apasarii de catre utilizatora butonului Test.alert("Butonul TEST a fost apasat!"). onClick = "functia_asociata".elements[0].elements.Note de curs 409 In definitie apare un atribut special.forms[0]. butonul Test este referit de document.forms[0].click() .elements[j].forms[0]. In listingul 30. Butonului cu numele intern test si eticheta Test ii este asociata o functie JavaScript numita mesaj.HTML <HTML> <HEAD> <TITLE>Apasare Buton</TITLE> <SCRIPT LANGUAGE="JavaScript"> <!-function mesaj() { window. dintr-un script Java. Obiectul button nu dispune decat de o singura metoda . Listing 3. Ele sunt accesibile dintr-un script Java prin referinta din tabloul document. care desemneaza functia JavaScript asociata butonului si evenimentul care declanseaza executia acesteia.length are valoarea 1) avand deci indexul j=0.forms[0].10 este exemplificata utilizarea unui astfel de buton.27 sunt reprezentate imaginile ferestrei browserului care afiseaza documentul Button. document. document.elements[0].value ("Test") si document. Evenimentul care declanseaza executia functiei este onClick care corespunde momentului cand browserul sesizeaza ca utilizatorul a clicait pe butonul respectiv. In cazul formularului din exemplul anterior. } //--> </SCRIPT> <FORM> <H2> Apasati butonul Test</H2> <INPUT TYPE="button" NAME="test" VALUE="Test" onClick="mesaj()"> </FORM> </HEAD> <BODY> </BODY> </HTML> In figura 30.10 . La apasarea butonului este automat executata functia JavaScript mesaj() care afiseaza o fereastra continand un mesaj de confirmare a evenimentului.elements[0] deoarece formularul este primul formular din document(si de altfel singurul ceea ce ne este confirmat de faptul ca document. unde i este i este numarul de ordine in document al formularului iar j este numarul de ordine al butonului in formular.forms[0].forms[0].click(). Butoanele sunt la randul lor obiecte.name ("test").HTML si fereastra de avertizare afisata de functia mesaj() care confirma apasarea butonului Test.

11 .forms[0]. In fereastra de mesaj este specificata atat starea actuala cat si starea implicita a casetei de validare. stabilita cu atributul CHECKED.value+ " a fost actionata. In listingul 30.410 CURS 30 Fig.alert("Caseta de validare " +document.fals .defaultChecked+". iar in figura 30.elements[0]. inainte ca utilizatorul sau vre-un script Java sa-l fi actionat.\nStarea implicita a casetei este " +document. ele sunt o extensie a tipului button avand aceleasi proprietati si metode ca si acesta.HTML <HTML> <HEAD> <TITLE>Caseta de Validare</TITLE> <SCRIPT LANGUAGE="JavaScript"> <!-function mesaj() { window.forms[0].elements[0].daca este validat sau FALSE .in caz contrar). O alta proprietate suplimentara a casetelor de validare este defaultChecked care specifica starea implicita a controlului la incarcarea documentului.elements[0].adevarat . } //--> </SCRIPT> <FORM> <H2> Validati caseta alaturata <INPUT TYPE="checkbox" .checked+ ".").11 este prezentat un exemplu de accesare a proprietatilor obiectului CHECKBOX.27 Controlul de tip "button" al unui formular Obiectele Checkbox (Casete de validare) La definirea aceste controale poate fi precizata ca si in cazul butoanelor o functie JavaScript asociata cu evenimentul onClick.forms[0].28 ferestrele afisate de browser dupa actionarea repetata a contrtolului.elements[0]. Listing 30.\nStarea actuala a casetei este " +document. In plus.Checkbox. casetele de validare mai au proprietatea checked care contine starea butonului sub forma unei valori booleene (TRUE .30.forms[0].name + " cu valoarea asociata " +document. Ca obiecte.

checked refera proprietatea checked a butonului i din grup. inainte ca utilizatorul sau vre-un script Java sa-l fi actionat (numai unul dintre butoanele grupului poate avea atributul CHEKED=true).test.value ne da valoarea butonului i din grup. .Note de curs NAME="TEST" VALUE="Test" CHECKED="true" onClick="mesaj()"> </H2> </FORM> </HEAD> </BODY> </HTML> 411 Fig. el are in in plus proprietatea length care specifica numarul de butoane cu interblocare cu acelasi nume care intra in componenta sa.28 Controlul de tip "checkbox" al unui formular Obiectele Radio (Grup de butoane interblocate) Obiectul radio desemneaza un grup de butoane interblocate fiind o extensie a tipului checkbox . document. Astfel daca grupul se numeste test.Proprietatea checked are valoarea booleana true daca butonul este validat si false nu este validat. obiectul este de fapt un tablou de length referinte la butoanele componente. atunci.12 si figura 30.30. Fata de obiectul checkbox.PROGRAMARE IN JAVA . Proprietatea defaultChecked specifica starea implicita a butonului interblocat la incarcarea documentului.29 exemplifica definirea si utilizarea unui formular continand ungrup de butoane interblocate. Deoarece din obiectul radio fac parte mai multe butoane. Proprietatea value contine valoarea asociata unui buton din grupul de butoane interblocate. Similar. Listingul 30. atunci document. stabilita cu atributul CHECKED.forms[i].test.forms[i].

forms[0].value+" = "+ document.length+ " butoane.value+" = "+ document.elements[0].test[2].forms[0].forms[0]. } //--> </SCRIPT> <FORM> <H2> Validati unul dintre butoanele cu interblocare de mai jos:</H2> <P>Buton 1 <INPUT NAME="test" CHECKED=true TYPE=RADIO VALUE="Butonul 1" onClick="mesaj()"></P> <P>Buton 2 <INPUT NAME="test" TYPE=RADIO VALUE="Butonul 2" onClick="mesaj(document.12 .Radio.checked+"\n").test[0].forms[0].test[1].forms[0].alert("Grupul de butoane interblocate "+ document.forms[0])"></P> </FORM> </HEAD> </BODY> </HTML> .forms[0].test[1].checked+"\n"+ document.forms[0].30.412 CURS 30 Fig.value+" = "+ document.forms[0].test.name+ " are in componenta sa "+ document.HTML <HTML> <HEAD> <TITLE>Butoane interblocate</TITLE> <SCRIPT LANGUAGE="JavaScript"> <!-function mesaj() { window.\nStarea butoanelor este:\n"+ document.29 Utilizarea obiectului radio Listing 30.checked+"\n"+ document.test[2].test[0].forms[0])"></P> <P>Buton 3 <INPUT NAME="test" TYPE=RADIO VALUE="Butonul 3" onClick="mesaj(document.

options[] .30 exemplifica definirea si utilizarea unui formular continand o lista de tip menu.forms[0].valoarea setata cu atributul VALUE sau implicit textul etichetei optiunii.text+" cu valoarea " +document. } //--> </SCRIPT> <FORM> <H2> Selectati una din optiunile din lista urmatoare:</H2> <SELECT NAME="test" onChange="mesaj().</OPTION> si selectedIndex care contine indexul optiunii selectate in tabloul options[] . El corespunde listei tip menu declarata in cadrul unui formular astfel: <SELECT NAME="nume lista"> <OPTION>Optiunea 1</OPTION> <OPTION>Optiunea 2</OPTION> <OPTION>Optiunea 3</OPTION> …………………………………….test.Select.name+ " are in componenta sa "+document.controlul este activat devenind tinta intrarilor de la tastatura.elements[0].test.tipul elementului.13 si figura 30.value).length+ " optiuni.forms[0]. length care specifica numarul de optiuni din lista.numele listei.options[index].selectedIndex.controlul este dezactivat (acesta nu mai este tinta intrarilor de la tastatura) si onChange .13 .status="Optiunea selectata = "+(index+1).forms[0].test. Obiectului i se pot asocia functii JavaScript ce vor fi executate la producerea unor evenimente cum ar fi onFocus .un sir de caractere care contine textul optiunii delimat in document de marcajele <OPTION>. defaultSelected continand o valoare booleana true daca optiunea era implicit selectata cu atributul SELECTED sau false in caz contrar.PROGRAMARE IN JAVA . onBlur . value .options[index]. Listingul 30.Note de curs 413 Obiectul Select ( Lista tip Menu sau Menu Derulant) Obiectul select este si el ca si obiectul radio compus din mai multe elemente selectabile. acelasi cu cel continut de proprietatea text.un tablou ale carui elemente sunt obiecte corespunzand optiunilor definite cu marcajele <OPTION>. <OPTION>Optiunea n</OPTION> </SELECT> Proprietatile obiectului sunt name . window.produs cand controlul este dezactivat (nu mai este tinta intrarilor de la tastatura) si optiunea selectata initial la activare in momentul onFocus s-a schimbat.</OPTION>.HTML <HTML> <HEAD> <TITLE>Butoane interblocate</TITLE> <SCRIPT LANGUAGE="JavaScript"> <!-function mesaj() { var index=document.\nOptiunea selectata este:\n " +document."> <OPTION SELECTED VALUE="UNU" >Optiunea 1</OPTION> <OPTION VALUE="DOI" >Optiunea 2</OPTION> <OPTION VALUE="TREI" >Optiunea 3</OPTION> .forms[0].test. type = "select" .alert("Lista Menu "+document. Elementele tabloului options[] sunt la randul lor obiecte avand proprietatile text . Listing 30. window.forms[0].

lipirea si inscriptionarea etichetei cu un "nume" corespunde declararii variabilei. Evident ca asa cum nu putem sa inscriem date pe discheta pana nu am formatat-o si etichetat-o. index . Aceste operatii s-au facut prin instructiunea declarativa: var index=document.30 . asa nu putem atribui valori unei variabile pana ce aceasta nu a fost declarata.selectedIndex "memorie" pe care am botezat-o mai simplu. Acest text de pe eticheta corespunde identificatorului (numelui) variabilei. se numeste variabila (tocmai pentru ca poate sa stocheze . Formatarea disketei.forms[0].31) . ceea ce il deosebeste de o constanta a carei valoare se stabileste obligatoriu la declarare si nu poate fi modificata sub nici un chip pe parcursul executiei scriptului). Inscrierea unor date pe discheta corespunde operatiei de atribuire a unei valori variabilei.elements[0]. Acest "botez" care consta in alocarea unui bloc de memorie necesar stocarii unor valori si in asocierea unui nume (identificator) blocului alocat pentru a-l putea accesa prin intermediul acestuia.una protejata la scriere si alta nu.selectedIndex.forms[0].414 </SELECT> </FORM> </HEAD> </BODY> </HTML> CURS 30 Fig. am stocat indexul optiunii selectate intr-o din meniu dat de document. pentru a o putea referi in textul scriptului.30.Utilizarea obiectului select In exemplul nostru. pentru a simplifica notatiile. Instructiunea declaratia var provine de la variable .diferite valori. Cea neprotejata la scriere corespunde unei variabile iar cealalta unei constante.elements[0].i se pot atribui . suplimentar am si stocat o valoare in blocul de memorie astfel construit. prin care.variabila. capabil sa memoreze diferite valori. Un astfel de obiect declarat cu var. Putem face o similitudine cu cazul a doua dischete (figura 30. . Textul inscris pe eticheta dischetei ne permite sa o identificam printre alte dischete si sa ne referim ulterior la ea.

Selectarea uneia dintre culori determina executarea functiei JavaScript schimbaCuloarea() care face ca fondul documentului sa capete culoarea aleasa din lista-menu. window.forms[0]. In figura 30.14 lista menu cu defilare astfel construita permite selectarea culorii de fond a documentului afisat."> <OPTION SELECTED VALUE="#C0C0C0" >Implicita</OPTION> <OPTION VALUE="#FFFFFF" >alba</OPTION> <OPTION VALUE="#00FFFF" >bleuciel</OPTION> <OPTION VALUE="#00FF00" >verde</OPTION> </SELECT> </FORM> </HEAD> </BODY> </HTML> .elements[0].HTML <HTML><HEAD> <TITLE>Background Colors</TITLE> <SCRIPT LANGUAGE="JavaScript"> <!-function schimbaCuloarea(colorList.bgColor=colorList.text+ " = "+colorList. document.index) { document.value)."+ (index+1)+" "+colorList.selectedIndex).Menu.31 Variabila si constanta Revenind la obiectul select sa mai analizam un exemplu care de aceasta data creaza un element de formular de tip lista-menu cu defilare.14 . Listing 30.Note de curs 415 Fig.options[index]. } //--> </SCRIPT> <FORM> <H2> Selectati culoarea de fond din lista urmatoare:</H2> <SELECT NAME="menu" SIZE=3 onChange="schimbaCuloarea(document.status="A fost selectata culoarea Nr.options[index].elements[0]. Lista-menu cuprinde ca optiuni mai multe denumiri de culori.PROGRAMARE IN JAVA . Folosind attributul SIZE al marcajului <SELECT> lista-menu poate fi afisata ca o lista menu cu defilare.32 este prezentata pagina afisata de browser dupa ce din lista-menu cu defilare s-a selectat optiunea a 3-a (avand textul "bleuciel" si valoarea "#00FFFF").value.options[index].forms[0].30. In exemplul din listingul 30.

selectedIndex reprezentand indexul in listamenu a optiunii selectate de utilizator.elements[0]. Prin acest mecanism.forms[0].forms[0].s electedIndex]. Astfel.32 .elements[0]. usureaza si depistarea unor eventuale erori si aducerea unor modificari ulterioare programului.elements[0] index = document.selectedIndex dupa care se trece la executia functiei.options[document. inainte de a se incepe executia functiei in timp ce pentru variabile alocarea de memorie se face la comanda (cu instructiunea declarativa var ) in timpul executiei functiei. Valoarea parametrilor formali este actualizata cu valoarea argumentelor folositi la apelul functiei (parametrii actuali). parametrii actuali au fost document.416 CURS 30 Fig.forms[0].elements[0].forms[0]. folosind parametrii formali.forms[0]. accesul la proprietatea value a optiunii selectate s-ar fi facut cu referinta: document. am obosit scriind asta.elements[0]. daca nu am fi folosit parametri. . parametrilor formali li se atribuie valorile parametrilor actuali adica in cazul functiei schimbaCuloarea() se fac atribuirile: colorList = document. implicit. Astfel. codul sursa al instructiunilor pentru accesarea propriertatilor obiectelor devine mai simplu de scris si mai intuitiv.value Ufffffffffffffffffff….value care este mult mai usor de scris dar si mai usor de inteles.30. Aceste argumente constitue parametrii formali ai functiei si sunt o varietate de obiecte similare variabilelor. functia schimbaCuloarea() are argumentele colorList si index. Asa.forms[0]. Folosind variabile si parametri formali codul sursa al programelor devine mai usor de inteles ceea ce. chiar referinta la listamenu din formularul nostru (elementul 0 din formular) si document.Lista menu cu defilare Si in acest program am simplificat notatiile prevaziand functia cu argumente. In urma selectarii unei optiuni din lista.options[index]. In cazul exemplului nostru.elements[0] reprezentand referinta la elementul 0 al formularului 0 din document adica.. Deosebirea consta in faptul ca pentru ei alocarea de memorie si atribuirea de valori se face automat. accesul la proprietatea value a optiunii selectate se face cu referinta: colorList.

care specifica numele intern al obiectului. Metodele obiectului sunt focus( ).continand textul curent continut de caseta de editare.produs cand controlul este dezactivat (nu mai este tinta intrarilor de la tastatura) si valoarea (textul) continuta initial la activare in momentul onFocus s-a schimbat. Listingul 30.controlul este dezactivat (acesta nu mai este tinta intrarilor de la tastatura).elements[0])"> </FORM> </HEAD> .15 si figura 30. onBlur .de email.".15 . Diferenta dintre ele consta in faptul ca obiectul text permite editarea textului pe un singur rand iar textarea pe mai multe randuri. acesta devenind tinta intrarilor de la tastatura. Proprietatile celor doua tipuri de obiecte sunt name .status="Inscrieti in caseta de editare adresa dvs. defaultValue valoarea implicita stabilita de atributul VALUE al marcajului <INPUT> cu care s-a definit controlul de tip text sau textarea in formular si in final type continand tipul controlului ("text" sau "textarea" ).HTML <HTML><HEAD> <TITLE>Text</TITLE> <SCRIPT LANGUAGE="JavaScript"> <!-function mesaj(textBox) { window.forms[0]. } //--> </SCRIPT> <FORM> <H2> Selectati caseta de editare si urmati indicatiile din bara de stare:</H2> <INPUT NAME="email" TYPE=text onFocus="indicatii()" onChange="mesaj(document. Obiectului i se pot asocia functii JavaScript ce vor fi executate la producerea unor evenimente cum ar fi onFocus .33 exemplifica definirea si utilizarea unui formular continand un control de tipul text. blur( ) .Text.Note de curs 417 Obiecte Text. TextArea si Password Controalele text si textarea.campul de editare este tinta intrarilor de la tastatura si utilizatorul a selectat o portiune din textul continut de acesta si onChange .care determina activarea controlului. componente ale unui formular sunt si ele tratate de JavaScript ca obiecte.controlul este activat devenind tinta intrarilor de la tastatura. Listing 30.PROGRAMARE IN JAVA . Proprietatile si metodele acestor obiecte sunt similare.alert("Ati introdus adresa de e-mail\n"+ textBox.value). } function indicatii() { window.determinand dezactivarea controlului (acesta nu mai este tinta intrarilor de la tastatura) si select ( ) care selecteaza textul din campul de editare. value . onSelect .

30.elements[j] dar si prin numele sau intern specificat cu atributul NAME = nume_element al marcajului <INPUT> in care a fost definit: this. un element j al formularului poate fi referit nu numai prin proprietatea this.418 </BODY> </HTML> CURS 30 Fig. Obiectul Navigator Acest obiect este folosit de un script Java pentru a obtine informatii despre browserul care il executa.forms[i].appCodeName Aceasta contine numele de cod al browserului. complicand textul sursa al scriptului.value Am vazut de asemenea ca o astfel de referinta este prea lunga si incomoda. In exemplele anterioare am simplificat notatia folosind variabile si parametri formali.elements[j]. cu deosebirea ca in acest caz textul tastat nu este vizibil fiind mascat cu asteriscuri(*). identificatorul this (acesta) refera acest formular fiind echivalent cu document.33 -utilizarea obiectul text Controlului de tip password din cadrul unui formular este de fapt o caseta de editare asemanatoare cu cea de tip text. Proprietatile sunt aceleasi ca si la obiectul text Obiectul This Am vazut ca accesul la valoarea unui element j al formularului i din document se face cu referinta document. atunci cand este plasat intre marcajele <FORM>. Proprietatile obiectului sunt: • proprietatea navigator. de exemplu pentru browserul Netscape aceasta proprietate este mozilla. Astfel.forms[i] si poate deci sa-l inlocuiasca. Limbajul JavaScript ofera insa si o cale mai naturala de a evita o astfel de constructie complicata.appName Aceasta contine c real al browserului.nume_element. .</FORM> de delimitare ale unui formular i al documentului curent. Pe de alta parte. • proprietatea navigator.

In tabelul 30. .plugins[] Aceasta proprietate este un tablou ale carui elemente specifica modulele plug-in instalate (de sunet. onBlur si onChange). imagini GIF.1 sunt enumerate toate obiectele discutate pe parcursul acestui capitol cu proprietatile. animatie. • proprietatea navigator.). Evenimente La discutarea obiectelor JavaScript discutate in acest capitol in unele cazuri ne-am folosit de termenul eveniment pentru a desemna momentele in care utilizatorul interactioneaza cu obiectul modificandu-i starea (onClick. Acestor evenimente le-am asociat in exemplele noastre functii JavaScript activate automat de browser la sesizarea producerii unui eveniment.PROGRAMARE IN JAVA .mimeType[] Aceasta proprietate este un tablou ale carui elemente specifica ce tipuri MIME de date este capabil sa afiseze browserul (text HTML. onFocus. • proprietatea navigator. returneaza o valoare booleana true daca browserul are activata interpretarea codului Java si false in caz contrar.Note de curs 419 • proprietatea navigator. numarul de versiune si platforma (de exemplu Win95). JPG. numele. sunet MID/WAVE etc. • proprietatea navigator.navigator.) Obiectul are si o metoda . Pentru unele obiecte cum ar fi ferestrele si documentele.appAgent Aceasta contine informatia completa asupra browserului inclusiv numele de cod.javaEnabled() care daca este apelata. metodele si evenimentele lor. evenimente sunt si incarcarea/creerea (onLoad) sau distrugerea (onUnload) lor ( asa cum si pentru noi nasterea si moartea sunt evenimente majore). Si acestor evenimente li se pot asocia functii JavaScript care sa fie activate la survenirea lor.appVersion Aceasta contine numarul de versiune al browserului. etc.

420 CURS 30 Tabel 30.1 Obiecte JavaScript OBIECT window Proprietati frames[] frames.length options[] continand aceste subproprietati: index name selected text value name value defaultValue type form submit() reset() onSubmit onReset button.length status self parent top opener length Metode alert() confirm() prompt() open() close() blur() focus() scroll() go() back() forward() write() writeln() clear() close() open() onLoad onUnload Evenimente onLoad onUnload onFocus onBlur onError history document title location lastModified loadedDate bgColor fgColor linkColor vlinkColor alinkColor forms[] forms. password blur() focus() select() onFocus onBlur onChange onSelect . reset click() onClick checkbox click() onClick radio click() onClick select onFocus onBlur onChange text.length name method action target elements[] name value type name value status defaultChecked checked type name value length defaultChecked checked type name length selectedIndex type options.length anchors[] anchors. submit. textarea.length links[] links.

Sign up to vote on this title
UsefulNot useful