Sunteți pe pagina 1din 310

PROGRAMARE IN JAVA - Note de curs

1

PROGRAMARE IN JAVA - Note de curs 1 Curs 1 Introducere Incepand cu anul 1977 incepe

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

2 CURS 1 masina. Fiecare comanda este reprezentata printr-un numar. Operanzii comenzii sunt si ele numere

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

PROGRAMARE IN JAVA - Note de curs 3 instructiuni cu codul masina a carui executie duce

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

4 CURS 1 Limbajul Java Numarul de calculatoare personale este de sute de milioane in toata

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 sci- fi. 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

PROGRAMARE IN JAVA - Note de curs 5 Limbajul FORTRAN avea o multime de vari ante

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

6 CURS 1 Figura 1.1 – mediul de dezvol tare al programelor Java HyperText Markup Language
6 CURS 1 Figura 1.1 – mediul de dezvol tare al programelor Java HyperText Markup Language

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.

PROGRAMARE IN JAVA - Note de curs

7

PROGRAMARE IN JAVA - Note de curs 7 Un program este un sistem de procesare a

Un program este un sistem de procesare a datelor. Putem spune ca este similar unui storcator de fructe. Asa cum introducand portocale si energie electrica in storcator obtinem la iesire suc, tot asa introducand in program datele initiale obtinem la iesire rezultatele. Un program de calculator este o masina de prelucrare a informatiei asemanator storcatorului de fructe dar cu deosebirea ca este mult mai

versatil. Un storcator de fructe, oricat de perfectionat, nu stie sa faca decat un singur lucru. 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. La fel ca si majoritatea masinilor, un program de calculator este facut din

diferite repere (parti) componente care interactioneaza intr-un mod definit cu precizie.

O astfel de colectie de componente constitue un sistem motiv pentru care programele

de calculator sunt numite uneori si sisteme informatice. In mod traditional, la elaborarea unui astfel de sistem de procesare a informatiei, proiectantul se concentreaza in special pe ce prelucrari trebuie sa faca programul. In cazul programelor complexe, problema este descompusa in subprobleme ce urmeaza a fi abordate separat. Daca unele din aceste subprobleme au inca un grad ridicat de complexitate, ele sunt la randul lor descompuse in subprobleme mai simple. O astfel de abordare de la complex la simplu prin detalieri succesive se numeste metodologie top-down de dezvoltare a programelor. Detalierea continua pana cand fiecare subproblema poate fi rezolvata de un subprogram numit subrutina, procedura sau functie in functie de limbajul de programare folosit. Programul obtinut are drept componente aceste proceduri care la executie interactioneaza pentru obtinerea rezultatului. In cazul unui program procedural datele sunt prelucrate similar cu prelucrarea unor piese intr-o linie de productie fiind transmise ca in figura 1.2 de la un punct de prelucrare la altul (de la o procedura la procedura) pana la procesarea completa.

la o pro cedura la procedura) pana la procesarea completa. Figura 1.2 – prelucrarea procedurala a

Figura 1.2 – prelucrarea procedurala a datelor

In cazul programelor orientate pe obiecte lucrurile stau oarecum diferit. 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. Aceste componente reunesc datele cu procedurile de prelucrare ale acestora intr-o singura entitate denumita obiect. La fel ca si obiectele din lumea reala, un astfel de obiect are o serie de proprietati – de exemplu culoare, dimensiune, coordonate. Totodata obiectul are un anumit comportament specific fiind capabil de a efectua in anumite conditii o serie de actiuni care ii modifica starea. 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. Putem reprezenta un obiect ca in Figura 1.3. Obiectul executa actiunile 1, 2 si 3 asupra proprietatilor la solicitari venite din exterior de la alte obiecte. Spunem ca aceste actiuni sunt publice, fiind accesibile din afara obiectului.

8

CURS 1

8 CURS 1 Figura 1.3 Reprezentarea unui obiect Actiunea 4 este “interna” obiectului si nu poate
8 CURS 1 Figura 1.3 Reprezentarea unui obiect Actiunea 4 este “interna” obiectului si nu poate

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

PROGRAMARE IN JAVA - Note de curs 9 asambla impreuna pe un sasiu (sertar cu sloturi)

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

10 CURS 1 elegant si revol utionar, numit mostenire , de a depasi aceasta limitare. Locul

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

11

PROGRAMARE IN JAVA - Note de curs 11 class HalloWorld { public static void main(String[] arguments){

class HalloWorld { public static void main(String[] arguments){ System.out.println(“Hallo world!”);

}

}

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).

mesajul Hello world! si se va termina (figura 1.4). Figura 1.4 – Compilarea si ex ecutia

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

12 CURS 1 Exercitii 1. Cand compilati un program, ce faceti de fapt? a. Il salvati

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

Salvati programul si

numele clasei din class HalloWorld{

incercati sa il compilati si executati. Comparati mesajele de eroare obtinute cu erorile

introduse.

}

in class halloWorld{

}.

PROGRAMARE IN JAVA - Note de curs

13

PROGRAMARE IN JAVA - Note de curs 13 Curs 2 Algoritmi si structuri de control Inainte

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

14 CURS 2 mai putin rigid in ce priveste respectarea regulilor sintactice. Pseudocodul nu este un

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

PROGRAMARE IN JAVA - Note de curs 15 Figura 2.1 – secventa Intai valoarea variabilei unghi
PROGRAMARE IN JAVA - Note de curs 15 Figura 2.1 – secventa Intai valoarea variabilei unghi

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.

16

CURS 2

16 CURS 2 Figura 2.2 – selectia simpla Mai exista o singura metoda de combibnare a
16 CURS 2 Figura 2.2 – selectia simpla Mai exista o singura metoda de combibnare a

Figura 2.2 – selectia simpla

Mai exista o singura metoda de combibnare a structurilor de control de acest tip si anume incuibarea. Structura descrisa mai sus poate transpusa in java astfel:

if(unghi >= 60) System.out.println(“Mai mare”);

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. Ca argument al instructiunii de selectie if poate fi prevazuta orice expresie care returneaza la evaluare o valoare de tip boolean.

Selectia dubla

Structura de selectie dubla if/else permite programatorului sa specifice o actiune alternativa care se executa in cazul conditia nu este indeplinita. Aceasta structura se scrie in pseudocod astfel

if(unghi >= 60) print “Mai mare” else print “Mai mic”

PROGRAMARE IN JAVA - Note de curs

17

PROGRAMARE IN JAVA - Note de curs 17 Figura 2.3 – selectia dubla Structura descrisa mai
PROGRAMARE IN JAVA - Note de curs 17 Figura 2.3 – selectia dubla Structura descrisa mai

Figura 2.3 – selectia dubla

Structura descrisa mai sus poate transpusa in java astfel:

if(unghi >= 60) System.out.println(“Mai mare”); else System.out.println(“Mai mic”);

Pe langa instructiunea if/else limbajul java mai prevede operatorul conditional ?: similar celui din limbajul C, avand sintaxa:

<expresie booleana>?<expresie1>:<expresie2> Daca la evaluarea expresiei booleene rezulta valoarea adevarat, operatorul evalueaza si intoarce valoarea expresiei 1 iar in caz contrar valoarea expresiei 2. Astfel instructiunea java:

System.out.println(unghi>=60? “Mai mare”:”Mai mic”);

va avea acelasi efect cu instructiunea if/else din exemplul anterior.Putem incuiba structurile de selectie duble ca in exemplul urmator:

if(unghi < 90) System.out.println(“Ascutit”); else if (unghi == 90) System.out.println(“Drept”); else System.out.println(“Obtuz”);

18

CURS 2

18 CURS 2 Schema logica corespunzatoare acestei s ecvente de instructiuni este cea din figura 2.4

Schema logica corespunzatoare acestei secvente de instructiuni este cea din figura 2.4

acestei s ecvente de instructiuni este cea din figura 2.4 Figura 2.4 – Incuibarea selectiilor duble

Figura 2.4 – Incuibarea selectiilor duble

Este important de subliniat ca componenta else a structurii este intotdeauna asociata de compilator cu ultimul if, indiferent de indentarea textului. Indentarea are doar rolul de a imbunatati claritatea programului. Daca dorim sa asociem o componenta else cu un alt if decat cel precedent trebuie sa folosim acoladele ca in exemplul urmator. Secventa de mai jos:

if(x > 10) if(y > 10) System.out.println(“x si y sunt mai mari ca 10”);

else System.out.println(“x este mai mic sau egal cu 10”);

va functiona incorect afisand mesajul x este mai mic sau egal cu 10 chiar daca x are valoarea 12 dar y este 5. Aceasta se datoreste faptului ca else este asociat cu if( y > 10) si nu cu if(x > 10), secventa corespunzand schemei logice din figura 2.5. Versiunea corecta se obtine folosind acoladele:

PROGRAMARE IN JAVA - Note de curs

19

PROGRAMARE IN JAVA - Note de curs 19 if(x > 10){ if(y > 10) System.out.println(“x si

if(x > 10){ if(y > 10) System.out.println(“x si y sunt mai mari ca 10”);

}else System.out.println(“x este mai mic sau egal cu 10”);

Acoladele {} indica compilatorului ca cel de al doilea if este incuibat in corpul primului si deci componenta else apartine primului if.

Instructiuni compuse

In mod normal instructiunea if accepta in corpul sau o singura instructiune. Daca prelucrarea ce trebuie executata este mai complexa si necesita mai multe instructiuni, acestea pentru a fi incluse in corpul lui if trebuiesc grupate intr-un bloc de instructiuni prin incadrarea intre acolade. Un astfel de bloc de instructiuni se numeste instructiune compusa. Exemplul urmator prezinta utilizarea instruciunilor compuse in corpul unei selectii duble:

if(unghi >= 60) System.out.println(“Mai mare”); else{ System.out.println(“Mai mic”); System.out.println(“Mai mariti unghiul!”);

}

In acest exemplu daca variabila unghi are valoarea mai mica decat 60 este executat blocul de doua instructiuni incadrate de acolade, afisandu-se pe doua randuri mesajele Mai mic si Mai mariti unghiul! . Daca nu s-ar fi folosit acoladele mesajul Mai mariti unghiul! ar fi fost afisat in oricare din situatii.

Selectia multipla

Fie urmatoarea instructiune formata din mai multe instructiuni de selectie incuibate:

if(unghi == 30)

System.out.println(“Unghi=30”);

else if (unghi == 45)

System.out.println(“Unghi=45”);

else if (unghi == 60)

System.out.println(“Unghi=60”);

else if (unghi == 90)

System.out.println(“Unghi=90”);

else System.out.println(“Alte valori”);

Pentru astfel de cazuri in care, in functie de valoarea intreaga pe care o ia o variabila, trebuie selectata si executata o anumita actiune din mai multe posibile (selectie multipla) limbajul java prevede instructiunea switch avand sintaxa:

20

CURS 2

20 CURS 2 switch ( <expresie intreaga> ){ case <val 1>: <actiune 1>; break; case <val

switch ( <expresie intreaga> ){ case <val 1>: <actiune 1>; break; case <val 2>: <actiune 2>; break;

case <val n>: <actiune n>; break; default:<actiune implicita>; break;

}

Aici daca valoarea intreaga obtinuta prin evaluarea <expresie intreaga> este <val 1> se va efectua <actiune 1>, daca este <val 2> se va efectua <actiune 2>, etc.Daca valoarea obtinuta nu este egala cu nici una din valorile <val1>,

<val2>,

Folosind aceasta instructiune, instructiunea compusa din exemplul precedent

poate fi inlocuita cu:

,<val

n> se va efectua <actiune implicita> specificata cu eticheta default.

switch(unghi){ case 30: System.out.println(“Unghi=30”); break; case 45: System.out.println(“Unghi=45”); break; case 60: System.out.println(“Unghi=60”); break; case 90: System.out.println(“Unghi=90”); break; default: System.out.println(“Alte valori”); break;

}

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). 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”. Actiunea este descrisa de directiva “Cumpara urmatorul obiect din lista”. Conditia verificata de fiecare data inaintea efectuarii acestei actiuni este “mai sunt obiecte de cumparat pe lista mea de cumparaturi?”. Daca aceasta conditie este satisfacuta se executa o noua cumparatura. Repetarea continua pana la epuizarea listei de cumparaturi, caz in care evaluarea conditiei intoarce un rezultat fals. O astfel de structura repetitiva se numeste ciclu cu testul la inceput. Actiunea constituie corpul ciclului iar conditia se numeste invariantul ciclului (denumire justificata de faptul ca acest ciclu se executa atat timp

PROGRAMARE IN JAVA - Note de curs

21

PROGRAMARE IN JAVA - Note de curs 21 valoarea rezultata din evaluar ea conditiei este invariant

valoarea rezultata din evaluarea conditiei este invariant adevarat). Ciclul se numeste ciclu cu testul la inceput deoarece evaluarea conditiei se face inainte de a se executa actiunea din corpul ciclului. Astfel este posibil ca aceasta actiune sa nu se execute nici

o data (daca conditia are din start valoarea fals). Sintaxa instructiunii while este:

while (<expresie booleana>) <instructiune> Instructiunea <instructiune> se repeta cat timp valoarea booleana obtinuta din evaluarea expresiei <expresie booleana> este adevarat. Instructiunea <instructiune> poate fi simpla sau compusa (bloc de instructiuni). Exemplul urmator prezinta utilizarea instructiunii while:

while(unghi < 360) unghi = unghi + 10;

In acest exemplu variabila unghi este marita ciclic cu 10 pana cand valoarea acesteia depaseste 360. Daca valoarea initiala a acestei variabile a fost 5, valoarea la iesirea din ciclu va fi 365. Daca valoarea initiala este un multiplu de zece dar mai mica de 360, valoarea finala obtinuta este 360. Daca insa valoarea initiala este egala sau mai mare ca 360, actiunea de incrementare a sa cu 10 nu are loc, ciclul terminandu-se fara

a se mai executa corpul sau deoarece conditia unghi < 360 este evaluata la valoarea fals de la inceput. Schema logica din figura 2.5 reprezinta structura repetitiva while din exemplul de mai sus.

din figura 2.5 repr ezinta structura repetitiva while din exemplul de mai sus. Figura 2.5 Structura

Figura 2.5 Structura repetitiva while

22

CURS 2

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

Structura de control repetitiva while

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

Figura 2.6 – structura repetitiva do/while

Sumar

Exercitii

PROGRAMARE IN JAVA - Note de curs

25

PROGRAMARE IN JAVA - Note de curs 25 Curs 3 Date, variabile, expresii Asa cum am

Curs 3

Date, variabile, expresii

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

26

CURS 3

26 CURS 3 expresiile aritmetice se evalueaza ca si in matematica prin efectuarea calculelor de la

expresiile aritmetice se evalueaza ca si in matematica prin efectuarea calculelor de la stanga la dreapta, efectuandu-se intai operatiile multiplicative (inmultiri, impartiri) si apoi cele aditive (adunari, scaderi). Ordinea de efectuare a operatiilor poate fi controlata de programator prin folosirea parantezelor “( )”. Ca si in algebra, o expresie poate sa contina ca termeni si variabile. In programare variabila este o locatie de memorie destinata stocarii pe parcursul executiei programului a unui anumit tip de date. In programare variabila este caracterizata prin nume si tip. Numele permite accesul la datele memorate in acea variabila. Tipul variabilei este acelasi cu tipul datelor pe care este prevazut sa le stocheze aceasta. Daca numele unei variabile apare ca termen intr-o exprsie, la evaluarea acesteia, el este inlocuit cu data memorata in variabila. 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, exista o diferenta intre instructiunea de atribuire si operatia de atribuire. In primul caz, valoarea rezultata din evaluarea expresiei <expresie> este stocata in locatia de memorie desemnata de <variabila>. In cel de al doilea caz <variabila> <op.atr><expresie> este ea insasi o expresie a carei valoare este chiar valoarea ce a fost memorata in variabila. o astfel de expresie, 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.

Numere intregi si reale

Inainte de a fi folosita intr-un program java, o variabila trebuie sa fie declarata. 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. De exemplu instructiunea:

int scorMaxim;

declara o variabila cu numele scorMaxim de tipul int. Denumirea tipulu int provine de la cuvintul englezesc Integer – intreg. Compilatorul va aloca pentru aceasta variabila o locatie de memorie dimensionata sa poata stoca numere intregi cu valori cuprinse intre -2,14 miliarde si +2,14 miliarde. Deoarece inca nu i s-a atribuit acestei variabile o valoare, continutul acestei locatii de memorie este neinitializat, continand o valoare arbitrara. Putem chiar la declarare sa atribuim variabilei o valoare intreaga prin operatorul de atribuire “=”:

int scorMaxim = 40000;

Instructiunea:

float punctajMediu;

declara o variabila cu numele punctajMediu de tipul float. 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

PROGRAMARE IN JAVA - Note de curs

27

PROGRAMARE IN JAVA - Note de curs 27 intregi, numerele reale sunt memorate ca o pereche

intregi, numerele reale sunt memorate ca o pereche de numere intregi. De exemplu modul de codificare in memorie a numarului real 123,456 poate fi prezentat simplificat astfel: numarul este transformat prin deplasarea virgulei in numarul real echivalent 0,123456 10 3 si memorat sub forma perechii de numere intregi (123456;3). Compilatorul va aloca pentru aceasta variabila o locatie de memorie suficient de incapatoare incat sa permita memorarea unor numere reale reprezentate in virgula mobila. Deoarece inca nu i s-a atribuit acestei variabile o valoare, continutul acestei locatii de memorie este neinitializat, continand o valoare arbitrara. Ca si in cazul variabilelor intregi putem atribui la declararea variabilei de tip float o valoare reala:

float punctajMediu = 123.456;

Numele variabilelor este un identificator. Un identificator poate fi orice combinatie de litere sau cifre cu conditia sa inceapa cu o litera. Caracterul “_” este asimilat literelor. 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, fie datorita unui caracter care nu este nici litera, nici cifra (-), ca in cel de al doilea caz.

Alte tipuri numerice de variabile

Pe langa tipul int limbajul Java mai prevede tipuri derivate pentru variabile care stocheaza date de tip intreg. Tipul byte determina dimensionarea locatiei de memorie pentru a pastra date cuprinse intre –128 si 127. Pentru o variabila de tip byte, compilatorul va aloca o locatie de memorie de un octet in timp ce pentru una de tip int memoria alocata este de 4 octeti. 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.223.372.036.854.775.808 si

9.223.372.036.854.775.807.

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. Pentru astfel de cazuri in locul tipului float se poate folosi tipul double (de la englezescul double precision – precizie dubla).

Caractere si siruri de caractere

Asa cum am aratat mai inainte, caracterele desemneaza simboluri grafice cum ar fi litere, cifre, semne de punctuatie, alte semne speciale care pot sa apara intr-un text. Pentru codificarea in memorie a datelor de tip caracter, fiecarui simbol grafic i se asociaza un cod numeric unic – un numar intreg cuprins intre 0 si 255. Exista mai multe standarde pentru codificarea caracterelor, unul dintre acestea fiind codul ASCII. In tabelul de mai jos sunt extrase codurile numerice asociate literelor si cifrelor:

Caracter

Cod ASCII

A-Z

65-90

a-z

97-122

0-9

48-57

28

CURS 3

28 CURS 3 Datele de tip caracter se reprezinta in cadrate de apostroafe. De exemplu ‘C’

Datele de tip caracter se reprezinta incadrate de apostroafe. De exemplu ‘C’ reprezinta caracterul C cu codul ASCII 67. O variabila de tip caracter (char) se declara si se initializeaza cu o instructiune de forma;

char key = ‘C’;

Sirurile de caractere se reprezinta incadrate cu ghilimele, ca de exemplu sirul “Hallo world!” afisat de primul nostru program java. Variabilele de tipul sir de caractere (String) se declara si se initializeaza ca in instructiunea de mai jos:

String mesaj = “Hallo world!”;

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 \” , numita secventa escape:

String mesaj = “Sunt student la Universitatea \“Politehnica\” din Bucuresti”;

Acelasi lucru este valabil si pentru caracterul apostrof care se va specifica cu secventa escape \’ ca si pentru caracterul backslash \ folosind \\ . 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

Caracter de control

\t

tab

\b

backspace

\r

carriage return

\f

formfeed

\n

new line

De exemplu folosind secventa escape \n instructiunea:

System.out.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, adevarat – true si fals - false. Pentru a memora astfel de date, pot fi declarate variabile de tipul boolean ca in exemplul de mai jos:

PROGRAMARE IN JAVA - Note de curs

29

PROGRAMARE IN JAVA - Note de curs 29 boolean sfirsitJoc = false; Exemplu de declarare a

boolean sfirsitJoc = false;

Exemplu de declarare a variabilelor in program

Vom aplica cele discutate mai sus intr-un program concret declarand diverse tipuri de variabile, initializandu-le si afisandule valorile. Aplicatia noastra va consta in definirea clasei Variabile:

class Variabile{ public static void main(String[] arguments){ // Declararea si initializarea variabilelor int scorMaxim=40000; double punctajMediu = 123.456; char key = ‘C’; String mesaj = “Hallo world!”; boolean sfirsitJoc = false; // Afisarea valorii variabilelor System.out.println(scorMaxim); System.out.println(punctajMediu); System.out.println(key); System.out.println(mesaj); System.out.println(sfirsitJoc);

}

}

Variabilele de tipurile discutate au fost declarate in cadrul metodei main care realizeaza si procesarea acestora. Spunem ca aceste variabile sunt locale metodei main.

Programul de mai sus va fi editat si salvat in fisierul Variabile.java. Comenzile de compilare si executie a programului continut de fisierul Variabile.java precum si rezultatele afisate sunt redate in figura 3.1.

precum si rezultatele afisate sunt redate in figura 3.1. Figura 3.1 – Compilarea si executia aplicatiei

Figura 3.1 – Compilarea si executia aplicatiei Variabile.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.

class MotanulPacepa{ public static void main(String[] arguments){ int greutate = 3; System.out.println(“Motanul Pacepa cintareste “ + greutate); System.out.println(“Motanul Pacepa viziteaza ulcica cu smintana“); greutate = greutate + 1; System.out.println(“Motanul Pacepa cintareste acum “ + greutate); System.out.println(“Motanul Pacepa descopera gimnastica aerobica“);

30

CURS 3

30 CURS 3 greutate = greutate - 2; System.out.println(“Motanul Pacepa cintareste acum “ + greutate);

greutate = greutate - 2; System.out.println(“Motanul Pacepa cintareste acum “ + greutate); System.out.println(“Motanul Pacepa cade in masina automata de ” + “spalat rufe“); greutate = greutate/2; System.out.println(“Motanul Pacepa cintareste acum “ + greutate); System.out.println(“Motanul Pacepa este clonat de 12 ori“); greutate = greutate + (greutate*12); System.out.println(“Cei 13 motani Pacepa cintaresc acum “ + greutate);

}

}

Programul de mai sus va fi editat si salvat in fisierul MotanulPacepa.java. Comenzile de compilare si executie a programului continut de fisierul Variabile.java precum si rezultatele afisate sunt redate in figura 3.2.

precum si rezultatele afisate sunt redate in figura 3.2. Figura 3.2 Compilarea si executia aplicatiei

Figura 3.2 Compilarea si executia aplicatiei MotanulPacepa.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 =. In cadrul acestor expresii au fost folositi operatori aritmetici binari care se aplica la operanzi de tip intreg. Acestia au fost reprezentati prin simbolurile + pentru adunare, - pentru scadere, * pentru si / pentru impartire. In una din expresii au fost folosite parantezele pentru a explicita ordinea de efectuare a operatiilor – ca si in algebra, la calculul expresiilor intai se executa operatiile din paranteze. De fapt o astfel de explicitare nu era necesara deoarece, asa cum am mai spus, implicit, la calculul expresiilor intai se efectueaza operatiile multiplicative si apoi cele aditive. De asemenea in cadrul programului apar frecvent ca argument al metodei System.out.println expresii cu rezultat de tip String cum ar fi de exemplu:

“Motanul Pacepa cade in masina automata de ” + “spalat rufe“;

Aici simbolul + desemneaza operatia de concatenare a sirurilor de caractere, avand ca rezultat un String format din inlantuirea celor doi operanzi de tip String. Data de tip String rezultata este tramnsmisa ca argument metodei System.out.println. Prezinta interes si expresiile de forma String + int in care cei doi operanzi sunt de tipuri diferite. In acest caz, in baza unor reguli precise de conversie automata si de compatibilitate a tipurilor de date pe care le vom discuta in detaliu la momentul

PROGRAMARE IN JAVA - Note de curs

31

PROGRAMARE IN JAVA - Note de curs 31 potrivit, termenul de tip int este convertit la

potrivit, termenul de tip int este convertit la tipul String dupa care se aplica operatorul de concatenare. Astfel in secventa:

int greutate = 3; System.out.println(“Motanul Pacepa cintareste “ + greutate);

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.

2. Deoarece celalalt termen al expresiei este de tip String, aceasta valoare intreaga este convertita automat la valoarea de tipul String “3”.

3. Cei doi termeni de tip String, “Motanul Pacepa cintareste “ si “3” sunt concatenati rezultand sirul “Motanul Pacepa cintareste 3” care este transmis pentru afisare metodei println a obiectului System.out.

Operatori pentru date de tip intreg

In exemplul precedent am vazut o serie de operatori care actioneaza asupra datelor de tip intreg (+, -, *, /). Pe langa acestia, limbajul Java ofera programatorului urmatorii operatori:

operatorul modulo reprezentat in expresii prin simbolul %. Acest operator binar calculeaza restul impartirii intregi a primului operand la cel de al doilea operand. Astfel expresia 14 % 3 are ca rezultat valoarea 2 (restul impartirii lui 14 la 3).

operatorii unari de incrementare reprezentati prin ++ si decrementare reprezentati prin -- au ca efect incrementarea respectiv decrementarea operandului cu 1. Acesti operatori accepta ca operanzi numai variabile de tip intreg. Actiunea acestor operatori depinde de locul pe care il ocupa in raport cu operandul. 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 operatia efectuata asupra operandului se numeste preincrementare/predecrementare. Astfel daca variabila x contine valoarea 3, continutul lui x dupa aplicarea operatorului ++ este 4 iar valoarea rezultata din evaluarea expresiei ++x este 4, aceasta expresie fiind echivalenta cu expresia x = x + 1. Similar stau lucrurile si in cazul predecrementarii lui x. Expresia --x are valoarea 2, iar x va contine valoarea 2 dupa aplicarea operatorului de predecrementare. Expresia –x este echivalenta cu expresia x = x – 1. Cu totul altfel stau lucrurile in cazul in care operatorul de incrementare/decrementare se afla amplasat dupa operand (il postfixeaza). In acest caz operatia se numeste postincrementare/postdecrementare. In acest caz la evaluarea expresiei se foloseste valoarea continuta de operand. Abia dupa ce expresia a fost evaluata continutul variabilei careia i s-a aplicat operatia de postincrementare/postdecrementare este marit/micsorat cu 1. 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. Abia dupa ce expresia a fost evaluata se incrementeaza x. Similar, dupa evaluarea expresiei x—valoarea rezultata este 3 iar variabila x va contine valoarea 2.

32

CURS 3

32 CURS 3 Foarte des in programe apar atribuiri de forma: <variabila x> = <variabila

Foarte des in programe apar atribuiri de forma:

<variabila x> = <variabila x><op><expresie>

unde <op> este unul din operatorii +, -, *, / sau % , cum ar fi de exemplu x= x + 2 sau greutate = greutate + (greutate*12). Limbajul Java ofera posibilitatea de a scrie simplificat astfel de expresii folosind operatorii += , -=, *=, /= si %=. Astfel in loc de x= x+2 vom putea scrie x+=2 iar inloc de greutate = greutate + (greutate*12) putem scrie greutate+= (greutate*12).

Precedenta Operatorilor

Asa cum am mai spus expresiile numerice se evalueaza de la stanga spre dreapta, intai efectuandu-se operatiile multiplicative (*, /,%) iar apoi cele aditive (+,-). Astfel de exemplu ordinea efectuarii operatiilor la evaluarea expresiei 6 * 2 / 4 + 5 * 3

este prezentata in figura 3.3. Trebuie avute in vedere urmatoarele aspecte:

1. Daca se codifica o expresie algebrica in program trebuie avuta in atentie ordinea de efectuarea operatiilor. Astfel de exemplu pentru a codifica expresia:

vom fi tentati sa scriem:

x

y

z

x / y * z

expresia: vom fi tentati sa scriem: x y ⋅ z x / y * z Figura

Figura 3.3 – Ordinea de efectuare a operatiilor si precedenta operatorilor

ceea ce este incorect. La evaluare se va imparti variabila x la variabila y iar rezultatul obtinut se va inmulti cu variabila z. Aceasta ar corespunde de fapt expresiei algebrice:

x

y

z

O varianta de codificarea corecta in program este expresia:

PROGRAMARE IN JAVA - Note de curs

33

PROGRAMARE IN JAVA - Note de curs 33 x / y / z impartind pe x

x / y / z

impartind pe x la y si rezultatul astfel obtinut la z. 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.

2. Neacordarea atentiei cuvenite ordinii de efectuare a operatiilor poate duce uneori la rezultate eronate. Astfel avand in vedere ca expresia 2/3 fiind o expresie cu termeni intregi, va avea si valoarea rezultata din evaluare tot o valoare intreaga. Astfel valoarea rezultata este 0. 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

3

12

Daca aceasta expresie o codificam in program:

2 / 3 * 12

desi totul pare corect, rezultatul obtinut va vi 0 deoarece operatiile efectuandu-se una cate una, de la stanga spre dreapta, impartirea 2/3 ne da rezultatul 0 care inmultit cu 12 ne va da tot 0 in loc de rezultatul corect 8. 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.

Implementarea ciclurilor cu contor

In rezolvarea unor probleme apare frecvent necesitatea repetarii unei procesari asupra unui numar cunoscut de seturi de date. Solutia consta in utilizarea unei variabile care sa contorizeze seturile de date procesate deja. Dupa fiecare procesare aceasta variabila este incrementata astfel ca in functie de valoarea acesteia se poate determina daca mai sunt date de procesat. Astfel daca variabila contor a depasit numarul cunoscut de seturi de date ce trebuiau procesate ciclul se termina. 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, care odata atinsa determina terminarea ciclarii (conditia de iesire din ciclu)

34

CURS 3

34 CURS 3 Ca exemplu sa proiectam algoritmul care asigura calculul si afisarea valorilor de la

Ca exemplu sa proiectam algoritmul care asigura calculul si afisarea valorilor de la 1 la 10. Schema logica a algoritmului este redata in figura 3.4.

10. Schema logica a algor itmului este redata in figura 3.4. Figura 3.4 – Ciclu cu

Figura 3.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; while(contor <= 10){ System.out.println(contor); contor++;

}

}

}

Asa cum am stabilit, variabila contor folosita in programul nostru pentru a tine evidenta numarului de procesari a fost initializata cu valoarea 1. La fiecare procesare valoarea acestei variabile este afisata dupa care aceasta este incrementata cu 1 (pasul de incrementare este 1). Procesarea se repeta pana cand variabila contor atinge valoarea 11, momentul in care conditia de ciclare contor<= 10 nu mai este satisfacuta. Tinand cont de proprietatile operatorului de postincrementare, programul poate fi simplificat comasand instructiunile:

System.out.println(contor);

contor++;

intr-o singura instructiune:

System.out.println(contor++);

PROGRAMARE IN JAVA - Note de curs

35

PROGRAMARE IN JAVA - Note de curs 35 Intr-adevar, aici, fiind folosit operatorul de postincrementare, valoarea

Intr-adevar, aici, fiind folosit operatorul de postincrementare, valoarea variabilei contor este intai afisata si abia dupa aceia aceasta este incrementata. Programul in aceasta versiune devine ceva mai compact:

class CicluCuContor{ public static void main(String[] arguments){ int contor = 1; while(contor <= 10) System.out.println(contor++);

}

}

Programul va fi editat in fisierul CicluCuContor.java. Comenzile de compilare si executie a programului continut de acest fisier precum si rezultatele afisate sunt redate in figura 3.5.

precum si rezultatele afisate sunt redate in figura 3.5. Figura 3.5 - Compilarea si executia aplicatiei

Figura 3.5 - Compilarea si executia aplicatiei CicluCuContor.java

Sumar

Pe parcursul acestui curs am tratat problemele fundamentale privind tipurile elementare de date ale limbajului Java, declararea variabilelor, operatori si utilizarea lor in expresii. Tipurile de date discutate au fost int, float, char, String si boolean. Au fost prezentati operatorii aritmetici +, -, *, /, %, ++, --, +=, -=, *=, /= si %=, operatorul de concatenare al sirurilor +, utilizarea parantezelor ( ) si operatorul de atribuire =. S-a discutat de asemenea ordinea de efectuare a operatiilor si precedenta operatorilor in evaluarea expresiilor. S-a prezentat structura si implementarea unui ciclu cu contor folosind structura repetitiva while.

Exercitii

1.

Determinati valorile fiecarei variabile dupa efectuarea calculelor. Se presupune ca initial fiecare variabila contine valoarea 10:

a)

produs *= x++;

b)

fractie /= ++x;

2.

Gasiti si corectati erorile din instructiunile de mai jos:

a)

while(c <= 10){ produs *= c; ++c;

36

CURS 3

36 CURS 3 b) if(x > 10) c) X += 3++; int x = 1, total;

b)

if(x > 10)

c)

X += 3++; int x = 1, total; while(x <= 10){ total += x; ++x;}

3. Ce va afisa programul urmator:

class Mister{ public static void main(String[] arguments){ int y, x =1, total = 0; while(x <= 10){ y= x*x; System.out.println(y); total +=y; ++x;

}

System.out.println(“Total =”+total);

}

}

PROGRAMARE IN JAVA - Note de curs

61

PROGRAMARE IN JAVA - Note de curs 61 Curs 6 Generarea numerelor aleatoare Vom studia in

Curs 6

Generarea numerelor aleatoare

Vom studia in continuare metoda random a clasei Math. Aceasta metoda genereaza o valoare aleatoare de tip double, n [0,1). Programul urmator genereaza 10 astfel de valori aleatoare:

class RandomTest{ public static void main(String[] arguments){ for(int i=1;i<=10;i++) System.out.println(Math.random());

}

}

Programul va fi editat in fisierul RandomTest.java. Comenzile de compilare si executie a programului continut de acest fisier precum si rezultatele afisate sunt redate in figura 6.1.

precum si rezultatele afisate sunt redate in figura 6.1. Figura 6.1- Compilarea si executia aplicatiei

Figura 6.1- Compilarea si executia aplicatiei RandomTest.java

De regula, valorile generate de aceasta metoda nu se gasesc in plaja de valori dorita de programator. De exemplu pentru a simula rezultatele aruncarii unui zar, valorile trebuie sa fie intregi si sa se gaseasca in domeniul [1,6]. Solutia in acest caz este de a calcula valorile necesare pe baza valorilor aleatoare generate de metoda random. In cazul zarului noile valori se vor calcula cu instructiunea:

val = 1+(int) (Math.random()*6);

Numarul 6 folosit pentru ajustarea valorii generate de metoda random se numeste factor de scalare. Programul urmator va simula “aruncarea“ de 10 ori a unui zar. Programul va fi editat in fisierul Zar.java. Comenzile de compilare si executie a

programului continut de acest fisier precum si rezultatele afisate sunt redate in figura

62

CURS 6

62 CURS 6 class Zar{ public static void main(String[] arguments){ int val; for(int i=1;i<=10;i++){ val =

class Zar{ public static void main(String[] arguments){ int val; for(int i=1;i<=10;i++){ val = 1+(int) (Math.random()*6); System.out.println(val);

}

}

}

= 1+(int) (Math.random()*6); System.out.println(val); } } } Figura 6.2- Compilarea si ex ecutia aplicatie i Zar.java

Figura 6.2- Compilarea si executia aplicatiei Zar.java

Pentru a ne convinge ca probabilitatea de aparitie a oricarui numar din cele 6 posibile este egala, vom executa programul urmator care simuleaza aruncarea de 6000 de ori a unui zar si calculeaza frecventa de aparitie a fiecarei valori.

class ZarTest{ public static void main(String[] arguments){ int val; int frecventa1=0,frecventa2=0,

frecventa3=0,frecventa4=0,

frecventa5=0,frecventa6=0;

for(int i=1;i<=6000;i++){ val = 1+(int) (Math.random()*6); switch(val){ case 1: frecventa1++; break; case 2: frecventa2++; break; case 3: frecventa 3++; break; case 4: frecventa4++; break; case 5: frecventa5++; break; case 6: frecventa 6++; break;

}

}

System.out.println(“val\tfrecventa”);

System.out.println(1+”\t”+frecventa1);

System.out.println(2+”\t”+frecventa2);

System.out.println(3+”\t”+frecventa3);

System.out.println(4+”\t”+frecventa4);

System.out.println(5+”\t”+frecventa5);

System.out.println(6+”\t”+frecventa6);

}

}

PROGRAMARE IN JAVA - Note de curs

63

PROGRAMARE IN JAVA - Note de curs 63 Programul va fi editat in fisierul ZarTest.java. Comenzile

Programul va fi editat in fisierul ZarTest.java. Comenzile de compilare si executie

a programului continut de acest fisier precum si rezultatele afisate sunt redate in figura

6.3.

precum si rezultatele afisate sunt redate in figura 6.3. Figura 6.3- Compilarea si execu tia aplicatiei

Figura 6.3- Compilarea si executia aplicatiei ZarTest.java

Analizand aceste rezultate observam ca frecventa de aparitie valorilor este aproximativ egala ( circa 1000 de apritii ale fiecarei valori). De asemenea, ruland de mai multe ori programul Zar.java constatam ca de fiecare data obtinem o alta secventa de 10 numere aleatoare.

Constante si variabile globale

Rescriind programul din exemplul anterior sub forma modulara am obtinut:

class ZarTest{ static int frecventa1=0,frecventa2=0,

frecventa3=0,frecventa4=0,

frecventa5=0,frecventa6=0;

static final int ARUNCARI=6000; static void simulareZar(int n){ int val; for(int i=1;i<=n;i++){ val = 1+(int) (Math.random()*6); switch(val){ case 1: frecventa1++; break; case 2: frecventa2++; break; case 3: frecventa3++; break; case 4: frecventa4++; break; case 5: frecventa5++; break; case 6: frecventa6++; break;

}

}

}

static void afisare(){ System.out.println("val\tfrecventa");

System.out.println(1+"\t"+frecventa1);

System.out.println(2+"\t"+frecventa2);

System.out.println(3+"\t"+frecventa3);

System.out.println(4+"\t"+frecventa4);

System.out.println(5+"\t"+frecventa5);

System.out.println(6+"\t"+frecventa6);

}

64

CURS 6

64 CURS 6 public static void main(String[] arguments){ simulareZar(ARUNCARI); afisare(); } } Aici metoda principala

public static void main(String[] arguments){ simulareZar(ARUNCARI); afisare();

}

}

Aici metoda principala main apeleaza doua metode “subalterne”, simulareZar si

afisare. Metoda simulareZar simuleaza aruncarea zarului de n ori si calculeaza

Numarul de aruncari n este parametrul

metodei simulareZar. Metoda afiseaza frecventele de aparitie ale valorilor 1 6

calculate de metoda simulareZar. Aici apar doua elemente noi. Frecventele de aparitie

sunt contorizate de variabilele de tip int frecventa1

ar fi fost locale metodei simulareZar ele nu ar fi acesate de metoda afisare si reciproc, daca ar fi fost declarate in corpul metodei afisare nu ar fi putut fi incrementate de metoda simulareZar fiindu-i necunoscute acesteia. Solutia a constat in declararea lor in afara corpului vreuneia din metodele clasei ZarTest devenind astfel variabile globale pentru metodele clasei ZarTest. Ele constitue de fapt o zona comuna de memorie pentru toate metodele clasei in cadrul careia au fost declarate. Spunem ca ele sunt vizibile pentru toate metodele clasei in care au fost declarate. Acelasi lucru este valabil si pentru variabila de tip int ARUNCARI. La declararea acesteia s-a folosit pe langa declaratia de tip si cuvantul rezervat Java final. Acesta o transforma intr-o variabila read-only adica intr-o constanta. Valoarea unei astfel de variabile se stabileste la declarare si nu mai poate sa fie modificata in timpul executiei programului. De regula, pentru claritatea programului, (desi nu este obligatoriu) astfel de variabile sunt denumite folosind majuscule pentru a pune in evidenta ca au o valoare fixata – ca sunt constante. Ca si metodele, variabilele globale din cadrul clasei ZarTest au fost declarate statice din motive pe care le vom discuta ulterior. Structura functionala a aplicatiei ZarTest.java poate fi reprezentata ca in figura 6.4.

frecventele de aparitie ale valorilor 1

6.

frecventa6.

Daca aceste variabile

ale va lorilor 1 6. frecventa6 . Daca aceste variabile Figura 6.4- Reprezentarea structurii func tionale

Figura 6.4- Reprezentarea structurii functionale a aplicatiei ZarTest.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.

PROGRAMARE IN JAVA - Note de curs

65

PROGRAMARE IN JAVA - Note de curs 65 Variabile automate O variabila este creata in momentul

Variabile automate

O variabila este creata in momentul declararii acesteia. La creerea variabilei ei i se aloca un bloc de memorie dimensionat sa pastreze date de tipul specificat la declararea variabilei. Acest bloc de memorie este asociat de catre compilator cu identificatorul (numele) variabilei si este accesat (inscris/citit) prin intermediul acestuia. Variabilele locale ale unei metode sunt create in momentul in care aceasta este apelata si incepe sa fie executata. Ele insa sunt distruse prin eliberarea blocurilor de memorie alocata, incetand sa mai existe in momentul in care executia metodei inceteaza, la revenirea in metoda apelanta. Astfel de variabile care au o durata de viata limitata se numesc automate. 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. 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 ). Denumim domeniu de existenta al variabilei portiunea de program in care aceasta variabila exista si poate fi accesata. 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. Din acest motiv valoarea continuta de o variabila automata la creere este arbitrara si trebuie sa fie explicit initializata inainte de a fi folosita. Portiunea de program in care o variabila poate fi accesata se numeste domeniu de vizibilitate a variabilei. Acest domeniu este stabilit de cateva reguli stricte. Astfel,

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.

Recursivitate

Existenta variabilelor automate permite implementarea in limbajul java recursivitatii. Acest mecanism consta in apelarea succesiva a unei metode de catre ea insasi. Asa cum o metoda poate apela o alta metoda, o metoda se poate apela pe ea insasi. 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, variabilele locale ale metodei apelante nu mai contin valorile pe care le contineau inainte de apel. Deoarece, asa cum am vazut variabilele automate sunt create la apelul metodei si distruse la terminarea executiei, fiecare apel recursiv va crea un nou set de variabile locale propriu. Astfel codul metodei apelate va prelucra propriul set de variabile fara a altera valorile setului de variabile proprietate a metodei apelante. Astfel, desi codul executat la fiecare apel recursiv este acelasi, memoria de date prelucrata de fiecare apel este diferita. 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. Factorialul este definit prin produsul:

n!=1 2

(n-1) n

66

CURS 6

66 CURS 6 O prima abordare ar fi utilizarea unui algoritm iterativ la calcularea acestui produs.

O prima abordare ar fi utilizarea unui algoritm iterativ la calcularea acestui

produs. Algoritmul propus este reprezentat prin schema logica din figura 6.5

propus este repre zentat prin schema logica din figura 6.5 Figura 6.5- Algoritmul iterativ de calcul

Figura 6.5- Algoritmul iterativ de calcul al factorialului

Programul repetitiva for este:

class FactorialIterativ{ static int factorial(int n){ int fact=1; for(int k=1;k<=10;k++) fact *= k; return fact;

Java

care

implementeaza

}

acest

algoritm

folosind

o

structura

public static void main(String[] arguments){ System.out.println(“10! =”+factorial(10));

}

}

Programul va fi editat in fisierul FactorialIterativ.java. Comenzile de compilare si executie a programului continut de acest fisier precum si rezultatele afisate sunt redate in figura 6.6.

precum si rezultatele afisate sunt redate in figura 6.6. Figura 6.6- Compilarea si executia aplicatiei Fa

Figura 6.6- Compilarea si executia aplicatiei FactorialIterativ.java

Sa vedem acum in figura 6.7 cum arata schema logica a algoritmului recursiv de

calcul al factorialului. Acest algoritm se bazeaza pe faptul ca formula de calcul a factorialului poate fi scrisa si intr-o forma recurenta:

PROGRAMARE IN JAVA - Note de curs

67

PROGRAMARE IN JAVA - Note de curs 67 n! = (n-1)! ⋅ n Figura 6.7- Algoritmul
PROGRAMARE IN JAVA - Note de curs 67 n! = (n-1)! ⋅ n Figura 6.7- Algoritmul

n! = (n-1)! n

Figura 6.7- Algoritmul recursiv de calcul al factorialului Algoritmul se bazeaza pe urmatorul mecanism. Doresc spre exemplu sa calculez

3!. Intrucat n==3 este diferit de 1, voi calcula 3! ca fiind produsul dintre 3 si factorialul lui (3-1) . Pentru a efectua acest produs trebuie sa calculez mai intai cat este (3-1)!. Pentru aceasta aplic acelasi algoritm. Deoarece 3-1 este 2 iar 2 este diferit de 1, 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)!. Pentru aceasta aplic acelasi algoritm. Intrucat 2-1 este egal cu 1, conform algoritmului, (2-1)! este 1. Acum pot sa ma intorc la calculul produsului precedent si sa il efectuez. Obtin (3-1)!=2*1=2. Avand aceasta valoare pot sa ma intorc cu inca un pas si sa calculez produsul 3*(3-1)! = 3*2=6. Aceasta este valoarea rezu ltata pentru 3!. Intr-adevar 3!=3*2*1.

acest algoritm folosind o structura de

P rogramul Java care implementeaza selectie if/else este:

class FactorialRecursiv{ static int factorial(int n ){ int fact;

if(n==1)

fact=1;

else

fact=n *factorial(n-1); System.out.println(n+"! ="+fact); return fact;

}

public static void main(String[] arguments){

}

}

factorial(10);

Programul va fi editat in fisierul FactorialRecursiv.java. Comenzile de compilare si executie a programului continut de acest fisier precum si rezultatele afisate sunt redate

68

CURS 6

68 CURS 6 in figura 6.8. Analizand rezultatele af isate de acest program vedem ca metoda

in figura 6.8. Analizand rezultatele afisate de acest program vedem ca metoda factorial s-a autoapelat de 10 ori si abia dupa aceia, cand n a devenit 1 a inceput sa

10 ori si abia dupa aceia, cand n a devenit 1 a inceput sa intoarca v

intoarca v

complet (1!) si terminand cu ultimul (10!). Figura 6.8- Compilarea si executia aplicatiei FactorialRecursiv.java

alorile calculate care au fost afisate incepand cu primul factorial c

alculat

P e baza celor doua exemple prezentate putem face o comparatie intre algoritmii recursivi si cei iterativi.

Algoritmii iterativi se construiesc folosind structuri de control repetitive (for, while, do/while); Amandoua categoriile de algoritmi se bazeaza pe repetarea unei anumite

procesari pana la obtinerea rezultatului dorit. in cazul algoritmilor iterativi

realizeaza explicit prin utilizarea unei structuri repetitive. In

cazul algoritmilor recursivi repetarea se realizeaza prin apeluri succesive ale metodei. Atat in cazul algoritmilor iterativi cat si in cazul celor recursivi incetarea repetitiei se face in urma unui test de terminare. La algoritmii iterativi repetarea se termina cand invariantul ciclului capata valoarea false. Recursia se incheie cand este detectat un caz de baza pentru care se cunoaste valoarea ce trebuie returnata. In aceste conditii, in cazul unor erori de logica in proiectarea algoritmului, este posibil ca atat ciclul iterativ cat si recursia sa fie infinite, 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 depas irea

spatiului de memorie maxim repartizat programului (prin alocari succesive de memorie - la fiecare recursie - pentru noi seturi de variabile locale).

aceasta se

Din cele de mai sus putem trage concluzii:

Algoritmii recursivi su nt 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 algo ritmii iterativi.

Algoritmii recursivi sunt mai periculosi putand duce la blocarea intregului sistem prin depasirea spatiului de memorie maxim admis.

PROGRAMARE IN JAVA - Note de curs

69

PROGRAMARE IN JAVA - Note de curs 69 In aceste conditii, algoritmii iterativi su nt preferabili

In aceste conditii, algoritmii iterativi su nt preferabili celor recursivi. La rezolvarea

unei probleme date

algoritm iterativ nu este evident.

lgoritm recursiv numai in cazul in care u n

s e va apela la un a

Supradefinirea metodelor

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, ordine sau tip). Acest mecnism se numeste supradefinire. La apelul metodei, compilatorul Java va identif ica dupa setul de valori transmi s ca parametri (parametrii actuali ai metodei)catre care din metodele cu acelasi nume sa directeze apelul. Supra definirea se foloseste de reg ula pentru a declara un grup de metode care efectueaza aceeasi proocesare dar asupr a unor date de tipuri diferite. In programul din exemplul urmator cele doua metode numite patrat realizeaz a operatia de ridicare la pute rea a 2-a a unei valori. Una din aceste metode are ca parametru o valoare de tip int si intoarce un rezultat de tip int. A doua metoda patrat are ca parametru o valoare de tip dou ble si intoarce un rezultat de tip double.

class Supradefinire{ static int patrat(int x){ return x*x;

}

static double patrat(double x){ return x*x;

}

public static void main(String[] arguments){ int a=5; float b=2.5; System.out.println(a ”^2 =”+patrat(a)); System.out.println(b ”^2 =”+patrat(b));

}

}

Programul va fi editat in fisierul Supradef

executie a pr in figura 6.9.

in

ire.java. Comenzile de compilare si

afisate sunt redate

ogramului continut de acest fisier precum si rezultatele

ogramului continut de acest fisier precum si rezultatele Figura 6.9- Compilarea si executia aplicatiei

Figura 6.9- Compilarea si executia aplicatiei Supradefinire.java

Structuri de date

Programele elaborate de noi pana acum rezolvau probleme de natura computationala, prelucrand date ce modelau obiecte specifice acestui domeniu. Calculatoarele pot insa prelucra informatii apartinand nu numai domeniului matematici. 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. Datele prelucrate de astfel de

70

CURS 6

70 CURS 6 programe au un caracter eterogen trebuind sa modeleze caracteristicile specifice obiectelor sau persoanelor

programe au un caracter eterogen trebuind sa modeleze caracteristicile specifice obiectelor sau persoanelor reale. Aceste caracteristici pot exprimate folosind tipurile de date primitive deja studiate. De exemplu informatia privind un obiect de inventar ar putea cuprinde urmatoarele denumirea, valoarea de inventar, numarul de inventar. In cazul gestiunii stocurilor informatia ar consta din denumire, cantitate, pret unitar. In cazul unui salariat informatia cu privire la acesta ar putea fi numele, varsta, vechimea, functia, adresa, telefon, starea civila, salariul, numarul legitimatiei, numarul de ore lucrate. Toate aceste date se pot exprima folosind tipurile de date cunoscute. Astfel pentru date de gen nume, denumire, adresa, telefon, numar de inventar, numar legitimatie se poate folosi tipul String. Pentru numar de ore lucrate, vechime, varsta se poate folosi tipul int. Pentru salariu si pentru cantitate poate fi folosit ipul double. Pentru o mai buna claritate din punct de vedere conceptual a programelor, toate datele privind un obiect 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, similar tipurilor primitive de date. O astfel de grupare cu structura eterogena (formata din date de tip diferit) se numeste structura de date . Ea modeleaza in program, cu precizia necesara, caracteristicile obiectului de i nventar, materialului sau a persoanei. In Java gruparea unor date intr-o structura se poate f ace in cadrul unui modul separat prin declaratiei unei clase ca in exemplul de mai jos:

public class Automobil{ String tip; int capacitate; int nr_usi; String culoare; St ring nr_circulatie; String serie_sasiu; boolean inmatriculat;

}

Declaratia clasei ca fiind publica permite accesul unei metode din exteriorul modulului la datele “incapsulate” in ea. Aceasta declaratie de clasa nu se refera de fapt la un automobil anume, continand doar caracteristicile specifice obiectelor din categoria automobilelor. Ea descrie de fapt atributele unei clase de obiecte, ceea ce

justifica utilizarea cuvantului rezervat class si constitue de fapt definirea unui tip nou de data care modeleaza un obiect din lumea reala. Aceasta descriere este folosita la alocarea de memorie cand se creeaza date de acest tip. Evident ca pentru a memora atributele u nui obiect real intr-o data de acest tip este nevoie de un bloc de memorie sufici ent de mare pentru a putea stoca toata informatia privind obiectul. Dimensionarea acestui bloc se face pe baza descrierii facute in declaratia clasei (prin sumarea dim ensiunii locatiilor de memorie necesare memorarii tuturor componentelor

struct

ur

ii).

In cazul claselor, d eclararea unei variabile de tipul respectiv nu duce si la

aloca rea

declaratia:

memoriei necesare stocarii informatiilor privind atributele obiectului. Astfel

Automobil masinaMea;

nu va aloca memorie pentru stocarea datelor privind tipul, culoarea, etc. autoturismului meu. Aceasta deoarece variabila masinaMea nu este chiar bloculd de memorie ci o referinta la un bloc de memorie. initial aceasta variabila are valoarea null deoarece inca nu refera nici un bloc de memorie. Alocarea unui ploc de memorie

PROGRAMARE IN JAVA - Note de curs

71

PROGRAMARE IN JAVA - Note de curs 71 se face cu operatorul new . Acesta are

se face cu operatorul new. Acesta are ca argument tipul de data care urmeaza sa fie continut de blocul de memorie alocat. Operatorul va intoarce referinta la blocul de m emorie dimensionat pe baza tipului specificat ca argument. Un astfel de mod de alocare a memoriei se numeste alocare dinamic a. Deci pentru a aloca memorie pentru pastrarea atributelor autoturismului meu, trebuie folosita secventa :

Automobil masinaMea= new Automobil();

acces ul la elementele structurii se face prin numele variabilei referinta urmat de operatorul deacces si numele atrib utului accesat:

masin aMea.tip = “Dacia”;

masinaMea.culoare=”Alb13”;

masinaMea.capacitate = 1300;

Alocarea dinamica de memorie asigura folosirea rationala a acesteia. Astfel, in momentul in care blocul de m emorie nu mai este necesar, prin simpla atribuire a valorii null variabilei referinta, acesta este disponibilizat putand fi alocat pentru satisfacerea altor cereri. De asemenea blocul de memorie este automat eliberat la distrugerea variabilei referinta. Programul care exemplifica definirea si utilizar ea structurilor de date este prezentat in continuare. El este alcatuit din doua module. Primul modul consta din clasa Automobil definita in fisierul Automobil.j ava:

public class Automobil{ String marca; int capacitate; String culoare;

}

Al doilea modul este constituit din clasa Structura care contine metoda main(). Codul acestei clase este continut de fisierul Structura.java:

class Structura{ public static void main(String[] argumen ts){ Automobil masinaMea = new Automobil (); masinaMea.marca="Dacia"; masinaMea.capacitate = 1300; masinaMea.culoare="Alb 13"; System.out.println("Masina mea"); System.out.println("marca:"+masinaMea.marca);

Sys tem.out.println("capacitate:"+masinaMea.capacitate); System.out.println("culoare:"+masinaMea.culoare);

}

}

Comenzile de compilare si executie a programului continut de aceste fisiere precum si rezultatele afisate sunt redate in figura 6.10. Se o bserva din listing ca la comanda de compilare a fisierului Structura.java, compilatorul a detectat referirea la clasa Automobil. Ca urmare a cautat fisierul Automobil.java in directorul curent (.\\)si l-a compilat automat ca facand parte din aplicatie.

72

CURS 6

72 CURS 6 Figura 6.10- Compilarea si executia aplicatiei Structura.java Sumar In cadrul acestui curs am
72 CURS 6 Figura 6.10- Compilarea si executia aplicatiei Structura.java Sumar In cadrul acestui curs am

Figura 6.10- Compilarea si executia aplicatiei Structura.java

Sumar

In cadrul acestui curs am abordat urmatoarele probleme

utilizarea metodei random a clasei Math pentru generarea numerelor aleatoare. S-a prezentat modul de scalare a acestor valori pentru a se incadra intr-un anumit

domeniu. Am elaborat un program prin care am testat repartizarea uniforma a probabilitatii de aparitie a valorilor generate de functia random. am abordat aspecte legate de domeiul de definitie si de vizibilitate a variabilelor.

s-au discutat tipurile de variabile automate, globale si constante.

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. 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. S-a prezentat si operatorul new si mecanismul alocarii dinamica a memoriei.

Exercitii

1. Elaborati un program Java care calculeaza si afiseaza volumul a 10 sfere folosind instructiunea:

volum = (4/3)*Math.PI*Math.pow(raza,3);

Valorile razei vor fi aleatoare, situandu-se in domeniul [5,25].

2.

Pentru fiecare set de numere de mai jos scrieti cate o singura instructiune care genereaza la intamplare si afiseaza unul din numerele setului.

a)

2, 4, 6, 8, 10;

b)

3, 5, 7,9, 11;

c)

6, 10, 14, 18, 22;

3.

Elaborati o metoda int putereIntreaga(int baza, int exponent) care calculeaza si intoarce valoarea :

baza exponent

PROGRAMARE IN JAVA - Note de curs

85

PROGRAMARE IN JAVA - Note de curs 85 Curs 8 Tablourile Java prevede o clasa “prefabricata”

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. Clasa Array defineste de fapt un grup de locatii succesive de memorie in care vor fi stocate date. Accesul la o anumita locatie se face prin intermediul numelui tabloului si a unui index intreg cuprins intre paranteze drepte, care specifica numarul locatiei la care se face accesul:

<nume tablou>[<index>] In figura 8.1 este prezentat un exemplu al unui tablou cu 10 elemente.

8.1 este prezentat un exemplu al unui tablou cu 10 elemente. Figura 8.1- Structura unui tablou

Figura 8.1- Structura unui tablou cu 10 elemente

Pe langa memoria alocata elementelor, obiectul tablou mai are in componenta variabila membru length (lungime) continand dimensiunea (numarul de elemente) tabloului. astfel in cazul tabloului din exemplul nostru, x.length contine valoarea 10. Sintaxa instructiunii de declarare a unui tablou este:

<tip> <nume>[] = new <tip>[<lungime>]; Pentru a declara tabloul din exemplul de mai sus vom folosi deci instructiunea:

int x[] = new int[10];

86

CURS 8

86 CURS 8 Aceasta instructiune contine de fapt in prima parte declararea unei variabile de tip

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. Putem deci sa descompunem instructiunea in doua:

int x[];// declararea variabilei de tip refrinta la un tablou de int x = new int[10];// Alocarea de memorie

Vom folosi un tablou reg pentru realizarea unei noi versiuni a clasei Stack elaborata in cursul precedent. De data aceasta stiva va fi implementata folosind un tablou de 4 elemente de tip double. Elementele tabloului vor corespunde celor 4 registri astfel:

reg[0] - registrul x reg[1] – registrul y reg[2] - registrul z reg[3] – registrul t Metodele push, pop si top vor fi adaptate pentru a lucra cu noua structura de date:

class Stack{ private double reg[]; public Stack(){// constructor stiva reg=new double[4]; for(int i=0;i<reg.length;i++)

reg[i]=0.0;

}

public void push(double val){// ridica stiva for(int i=reg.length –1;i>0;i--)

reg[i]=reg[i-1];

reg[0]=val;

}

public double pop(){//coboara stiva double val=reg[0]; for(int i=0;i<reg.length-1;i++)

reg[i]=reg[i+1];

reg[3]=0.0

return val;

}

public double top(){return reg[0];}//intoarce varful stivei

}

Inlocuind fisierele Register.java si Stack.java cu acest modul editat intr-un nou fisier Stack.java programul CalcTest va functiona fara sa-i aducem modificari si fara a modifica nici modulul din Calculator.java. Listingul din figura 8.2 demonstraeaza acest lucru. Vom sterge in prealabil fisierele Stack.class si Register.class de pe disc. La incercarea de a executa programul CalcTest.class acesta va incarca modulul Calculator.class care la randul sau va incerca sa incarce modulul Stack.class. Deoarece nu il gaseste fiind sters, interpretorul va semnala eroarea (clasa Stack nu este definita) si isi va inceta activitatea. Acum vom edita fisierul Stack.java in noua sa versiune si il vom compila rezultand modulul Stack.class necesar functionarii modulului Calculator.class. Executand acum programul CalcTest.class acesta va functiona normal afisand aceleasi rezultatele ca si in versiunea sa precedenta. Acest exemplu demonstreaza cat de usor pot fi facute modificari in programele proiectate orientat pe obiecte. 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. Operatia a decurs similar inlocuirii unui procesor pe placa de baza cu altul de acelasi tip (compatibil la nivel de pini) dar mai performant.

PROGRAMARE IN JAVA - Note de curs

87

PROGRAMARE IN JAVA - Note de curs 87 Figura 8.2- Inlocuirea modulului Stac k.class in programul
PROGRAMARE IN JAVA - Note de curs 87 Figura 8.2- Inlocuirea modulului Stac k.class in programul

Figura 8.2- Inlocuirea modulului Stack.class in programul CalcTest.java

Referinta this

La instantierea unei clase intr-un obiect acesta este referit printr-o valoare referinta. La apelul oricarei metode aceasta primeste ca parametru implicit referinta la obiectul careia ii apartine metoda. Aceasta referinta este accesibila prin parametrul implicit this. Sa ilustram aceasta printr-un exemplu:

Fie clasa:

class ThisData{ private int data; public ThisData(int val){ data = val;

}

public toString(){ int data=0; return “this.data =”+this.data;

}

}

Constructorul clasei initiaza variabila data cu valoarea primita ca parametru. Metoda toString formeaza si intoarce un string continand si data setata de constructor. In cadrul metodei am declarat o variabila locala de acelasi tip int si cu acelasi nume data initializata cu 0. Aceasta “mascheaza” in mod normal variabila membru data care astfel devine inaccesibila. Metoda toString primeste insa ca parametru implicit referinta this la obiectul din care face parte. Folosind aceasta referinta pot sa accesez variabila membru data a obiectului referit de this. Iata si clasa de testare a acestui mecanism:

class ThisTest{ public static void main(String[] arguments){ ThisData a=new ThisData(1), b=new ThisData(2);//crearea obiectelor a si b System.out.println(a.toString());//Afisare obiect a System.out.println(b.toString());//Afisare obiect b

}

}

Listingul din figura 8.3 ne arata comenzile de editare, compilare si executie a acestui program.

88

CURS 8

88 CURS 8 Figura 8.3- Testarea parametrului this O alta aplicatie a parametrului this este apelul
88 CURS 8 Figura 8.3- Testarea parametrului this O alta aplicatie a parametrului this este apelul

Figura 8.3- Testarea parametrului this O alta aplicatie a parametrului this este apelul in lant al metodelor unui obiect. Sa o urmarim pe un exemplu. Definim clasa Timp:

class Timp{ private int ora, min, sec; // Constructori public Timp(){

setTimp(0,0,0);

}

public Timp(int h){setTimp(h,0,0);} public Timp(int h,int m){setTimp(h,m,0);} public Timp(int h, int m, int s){ setTimp(h,m,s);} // Metode public void setTimp(int h,int m, int s){ setOra(h);setMin(m);setSec(s);return this;

}

public Timp setOra(int h){ ora=((h>=0 && h<24)?h:0); return this;

}

public Timp setMin(int m){ min=((m>=0 && m<60)?m:0); return this;

}

public Timp setSec(int s){

sec=((s>=0 && s<60)?s:0); return this;

}

public int getOra(){return ora;} public int getMin(){return min;} public int getSec(){return sec;} public String toString12h(){ return ((ora==12 || ora==0)? 12:ora%12)+”:”+

(min<10?”0”:””)+min+”:”+(sec<10?”0”:””)+sec+

(ora<12 ?”AM”:”PM”);

}

public String toString24h(){ return ora+”:”+(min<10?”0”:””)+min+”:”+(sec<10?”0”:””)+sec;

}

}

Sunt trei aspecte de subliniat cu privire la definitia acestei clase. Primul este supradefinirea constructorului Timp. Al doilea aspect priveste returnarea parametrului implicit this de catre metodele setOra, setMin si setSec. Valoarea returnata va fi folosita pentru exemplificarea inlantuirii apelurilor acestor metode. al treilea aspect priveste prevederea metodelor set si get pentru accesul variabilelor membre private. Aceste metode permit accesul din exterior la variabilele private dar metodele de tipul set efectueaza o validare a datelor inscrise in aceste variabile.

PROGRAMARE IN JAVA - Note de curs

89

PROGRAMARE IN JAVA - Note de curs 89 Modulul de test al acestei clase este: class

Modulul de test al acestei clase este:

class TimpTest{ public static void main(String[] arguments){ Timp t=new Timp(); t.setOra(14).setMin(7).setSec(30);//Apelul inlantuit

System.out.println(t.toString12h());

System.out.println(t.toString24h());

System.out.println(“Timp nou:\n”+ t.setTimp(20,20,20).toString12h());// Apel inlantuit

System.out.println(t.toString24h());

}

}

Apelul inlantuit:

t.setOra(14).setMin(7).setSec(30)

se evalueaza de la stanga spre dreapta (operatorul de acces . se asociaza de la stanga la dreapta). Astfel intai se executa metoda t.setOra(14) . Aceasta intoarce o referinta la obiectul t astfel incat in continuare se executa t.setMin(7).setSec(30). Deci se va executa metoda t.setMin(7). Intrucat si aceasta intoarce o referinta la t, in final se va executa si t.setSec(30). Cele de mai sus sunt valabile si pentru cel de al doilea apel inlantuit din program. Listingul compilarii si executiei acestui program este redat in figura 8.4:

si executiei acestui program este redat in figura 8.4: Figura 8.4- Apelul inlantuit al metodelor Membrii

Figura 8.4- Apelul inlantuit al metodelor

Membrii statici ai unei clase

In mod normal, am vazut ca memoria pentru instantele unei clase se aloca dinamic, folosind explicit operatorul new. Daca totusi membrul unei clase se declara ca fiind static, compilatorul le va aloca automat memorie in momentul in care clasa este incarcata. Pe de o parte acest mecanism permite accesul acestor membri (daca sunt publici) fara a crea vre-o instanta a clasei. Este astfel cazul functiei main declarata public static. Este de asemenea cazul claselor studiate de noi, Math si System, ale caror metode pot fi apelate fara a crea instante ale acestor clase. Accesul membrilor statici ai clasei se face cu operatorul de acces “.” precedat de numele clasei ( de exemplu Math.pow(2,3)). O clasa poate sa aibe atat membri statici cat si membri dinamici. Numai membrilor statici ale clasei li se aloca memorie si numai acestia pot fi accesati prin intermediul numelui clasei. Pentru a accesa membrii dinamici trebuiesc create dinamic instante ale clasei. La crearea instantelor unei astfel de clase, membrilor dinamici ai acesteia trebuie sa li se aloce memorie folosind operatorul new. Blocul de memorie se aloca membrilor statici o singura data, la incarcarea clasei, si este comun tuturor instantelor clasei spre deosebire de blocurile de memorie alocate dinamic, proprii fiecarei instante create (figura 8.5).

90

CURS 8

90 CURS 8 Figura 8.5- Alocarea statica si dinamica a memoriei pentru membrii clasei Accesul unei
90 CURS 8 Figura 8.5- Alocarea statica si dinamica a memoriei pentru membrii clasei Accesul unei

Figura 8.5- 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 . Sa exemplificam utilitatea existentei unei zone comune de memorie pentru toate instantele unei clase, 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. Rebelii stiu ca un astfel de atac are sanse de succes numai daca numarul lor de nave este mai mare sau egal cu 10. Fiecare navaa flotei Rebelilor este modelata de un obiect obtinut prin instantierea clasei Nava. Pentru a declansa atacul, fiecare nava trebuie sa cunoasca numarul de nave de care dispune flota Rebelilor. In momentul in care acest numar este mai mare sau egal cu 10 nava devine agresiva, deschizand focul asupra bazei stelare. Acest numar poate fi cunoscut tuturor navelor implicate prin prevederea unei variabile comune nrNave, accesibile fiecarei instante. Aceasta variabila este incrementata ori de cate ori in formatie soseste o noua nava (se creaza o noua instanta a clasei Nava).

class Nava{ private static int nrNave=0; private String nume; public Nava(String _nume){ //Constructor nrNave++;nume=_nume; System.out.println(nume+“ in formatie”);

}

public void actiune(){if(nrNave >= 10) ataca();else asteapta();}

private void ataca(){System.out.println(nume + “ ataca baza”);} private void asteapta(){ System.out.println(nume + “ gata de lupta”);

}

}

class StarWars{ public static void main(String[] arguments){ Nava flota[]=new Nava[10]; for(int i=1;i<10;i++) flota[i]=new Nava(“Red”+i); for(int i=1;i<10;i++) flota[i].actiune(); flota[0]= new Nava(“Red Leader”); for(int i=0;i<10;i++) flota[i].actiune();

}

}

PROGRAMARE IN JAVA - Note de curs

91

PROGRAMARE IN JAVA - Note de curs 91 Figura 8.6- Editarea, compilar ea si executia programului
PROGRAMARE IN JAVA - Note de curs 91 Figura 8.6- Editarea, compilar ea si executia programului

Figura 8.6- Editarea, compilarea si executia programului StarWars Comenzile de editare, compilare si executie a fisierelor programului precum si rezultatele afisate sunt redate in figura 8.6. Codul de testare a clasei Nava este editat in fisierul StarWars.java. I cadrul metodei main este declarat un tablou flota de 10 elemente de tip Nava. Elementele acestui tablou sunt referinte la obiecte din clasa Nava. Elementele tabloului, initializate implicit cu null la creere, primesc valori in cadrul unui ciclu for pe masura ce noi instante ale clasei Nava sunt create. Ciclul for urmator apeleaza metoda actiune a fiecarui obiect de tip Nava astfel creat. Deoarece numarul de nave, continut de variabila comuna nrNave, este mai mic decat 10, nici una din ele nu ataca baza. Abia cand, prin “sosirea” navei amiral, 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.

Programarea orientata pe obiecte

In aceasta sectiune vom discuta tehnologiile de baza aplicate in programarea orientata pe obiecte (POO). Acestea sunt mostenirea si polimorfismul. Mostenirea este o forma de refolosire a modulelor deja elaborate care permite definirea de noi clase pornind de la o clasa existenta. 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). 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. Astfel de clase nu pot fi utile la crearea de obiecte dar pot fi folosite in calitate de clase de baza ale caror

92

CURS 8

92 CURS 8 subclase sa implementeze prin supradefinire algoritmi concreti pentru metodele respective adecvati procesarii

subclase sa implementeze prin supradefinire algoritmi concreti pentru metodele respective adecvati procesarii unor tipuri de date concrete. Acest mecanism este numit polimorfism. 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. 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. Aceste mecanisme deschid perspective deosebite in ingineria software in ce priveste eficienta in proiectarea si implementarea unor pachete de programe complexe. Vom analiza in continuare pe baza unor exemple folosirea celor doua mecanisme POO in elaborarea programelor.

Mostenirea

Vom defini in continuare o clasa Mamifer:

public class Mamifer{ public String nume; public Mamifer(String _nume){nume = _nume;}//Constructorul public void dormi() {System.out.println(nume +“: ZZZZ ZZZZZZZZ ZZZZ”);}

}

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);}//Constructorul public void vorbeste(){System.out.println(nume+“: Ham!”);}

}

public class Motan extends Mamifer{ public Motan(String nume){super(nume);}//Constructorul public void vorbeste(){System.out.println(nume +“: Miau!”);}

}

public class Postas extends Mamifer{ public Postas(String nume){super(nume);}//Constructorul public void vorbeste(){System.out.println(nume +“: Posta!”);}

}

Constructorii aceste subclase invoca constructorul superclasei referit de super. Sa folosim aceste clase in programul urmator:

class Specii{ public static void main(String[] arguments){ Dulau dulau=new Dulau (“Grivei”); Motan motan = new Motan (“Pacepa”); Postas postas = new Postas (“Nae”); System.out.println(“Intai cerem motanului sa vorbeasca:”); motan.vorbeste(); System.out.println(“Acum este momentul sa vorbeasca postasul:”); postas.vorbeste(); System.out.println(“Iar acum sa vorbeasca dulaul:”); dulau.vorbeste(); System.out.println(“Este timpul ca toti sa faca nani.”); motan.dormi();dulau.dormi();postas.dormi();

}

}

PROGRAMARE IN JAVA - Note de curs

93

PROGRAMARE IN JAVA - Note de curs 93 Comenzile de compilare si executie a fisier elor

Comenzile de compilare si executie a fisierelor programului precum si rezultatele afisate sunt redate in figura 8.7.

precum si rezultatele afisate sunt redate in figura 8.7. Figura 8.7- Comenzile de compila re si

Figura 8.7- Comenzile de compilare si executie programului Specii Pentru definirea unei subclase nu trebuie modificat si deci nici recompilat codul superclasei. Programatorul nici nu trebuie sa dispuna de codul sursa al superclasei ci numai de modulul .class obtinut din compilarea acesteia. Sa folosim acest mecanism pentru a extinde functiunile calculatorului stiva elaborat in cursul trecut transformandu-l intr-un calculator stiintific definit de clasa CalculatorSt. Vom realiza aceasta prin adaugarea urmatoarelor operatii:CS – schimbarea semnului; INV - 1/x; SQRT - x 1/2 ; SQR - x 2 ; POW - x y ; EXP - e x ; LOG - ln(x);

class CalculatorSt extends Calculator{ public CalculatorSt(){// Constructorul super();//apelul constructorului superclasei

}

public void cs(){s.push(-s.pop());display();} public void inv(){s.push(1/s.pop());display();} public void sqrt(){s.push(Math.sqrt(s.pop()));display();} public void sqr(){ double a= s.pop(); s.push(a*a);display();

}

public void pow(){s.push(Math.pow(s.pop(),s.pop()));display();} public void exp(){s.push(Math.exp(s.pop()));display();} public void log(){s.push(Math.log(s.pop()));display();}

}

Se vede ca aceasta clasa foloseste in noile metode adaugate accesul la stiva s si la metoda display a superclasei Calculator. Aceasta ridica o problema deoarece acestti membri ai superclasei au fost declarati privati si deci nu pot fi accesati din afara clasei. Nu este bine sa-i declaram publici din motivele enuntate la momentul respectiv. Pentru ca totusi sa –i putem accesa din subclasele derivate se va folosi specificatorul protected. Membrii declarati protected ai superclasei vor fi accesibili din subclase si inaccesibili din afara clasei de baza si a claselor derivate din aceasta. 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. In mod normal superclasa trebuie astfel proiectata incat sa nu necesite modificarea si recompilarea codului sursa. Vom putea acum sa scriem un program care sa calculeze o expresie continand si functiile implementate mai sus cum ar fi:

-9 5 2 +

e 25

94

CURS 8

94 CURS 8 Programul care efectueaza calcul acestei expres ii folosind o instanta a aceastei clase

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();// constructor c.enter(9); c.cs();c.enter(5);c.sqr(); c.mul(); c.enter(2); c.enter(5);c.mul();c.exp();c.sum();

}