Programare Java Curs – 2 TABLOURI Tablourile reprezinta o modalitate de a pastra o lista de elemente cu aceleasi tipuri de date primitive sau de clase . Fiecare element al listei este pastrat intr-o locatie proprie , numerotata astfel incat informatia poate fi usor accesata . Tablourile pot contine orice tip de informatie pastrata in mod normal intr-o variabila , insa , o data creat , tabloul nu poate fi folosit decat pentru acel tip de date . De exemplu , putem avea un tablou de intregi , un tablou de obiecte String sau un tablou de tablouri insa nu putem avea un tablou care sa contina atat siruri cat si intregi . Pentru a crea un tablou in Java trebuie sa urmarim pasii de mai jos : 1. 2. 3.
Declaram o variabila care sa refere un tablou Cream un obiect de tip tablou si il atribuim variabilei tablou Stocam informatia in tabloul respectiv
DECLARAREA VARIABILELOR TABLOU Primul pas de mai sus este declararea variabilei care va referi tabloul . Variabilele tablou indica tipul de obiecte sau de date pe care le va contine tabloul , precum si numele acestuia . Pentru a le diferentia de declaratiile normale de variabile se adauga o pereche de paranteze patrate [] la tipul de obiecte sau de date sau la numele variabilei . Exemplu : String cuvinte[]; Point lovituri; int salariu[]; Exemplele de mai jos sunt si ele valide : String[] cuvinte; Point[] lovituri; int[] salariu; CREAREA DE OBIECTE TABLOU Dupa ce declaram variabila tablou , urmatorul pas este de a crea un obiect tablou si de a-l atribui unei variabile . Exista mai multe modalitati : -
folosim operatorul new initializam direct continutul tabloului
Deoarece tablourile sunt obiecte Java putem folosi operatorul new pentru a crea o noua instanta a unui tablou : String[] numeJucatori=new String[10]; Aceasta instructiune creaza un tablou de siruri cu 10 pozitii , care poate contine obiecte String . Atunci cand cream un obiect tablou folosind operatorul new , trebuie sa indicam cate pozitii urmeaza sa contina acesta . Aceasta instructiune nu introduce nici un fel de obiecte String pe aceste pozitii . Obiectele tablou pot contine si tipuri primitive cum ar fi intregi sau valori booleene , nu numai obiecte :
int[] temp=new int[99]; Atunci cand cream un obiect tablou folosind operatorul new toate pozitiile sale vor fi initializate automat ( cu 0 cele numerice , cu false pentru boolean , cu ‘/0’ pentru tipul caracter si cu null pentru obiecte ). OBS : null nu este echivalent cu zero sau cu caracterul “/0” , ca in cazul limbajului C Putem crea si initializa un tablou in acelasi timp . In loc sa folosim operatorul new pentru a crea noul obiect tablou includem elementele tabloului intre {} , separate prin virgula : String[] nume={“Ion” , “Andrei”, “Mihai” }; Fiecare dintre elementele dintre acolade trebuie sa fie de acelasi tip cu variabila tablou . Atunci cand cream un tablou cu valori initiale in acest fel , tabloul are dimensiunea egala cu numarul de elemente incluse . Exemplul anterior creaza un tablou de obiecte String , denumit nume , care contine trei elemente . ACCESAREA ELEMENTELOR TABLOULUI Dupa ce s-a creat un tablou cu valori initiale putem accesa , modifica si testa valorile fiecarei locatii a acestuia . Valoarea unei locatii este accesata cu numele tabloului , urmat de pozitia ei in cadrul acestuia , incadrata intre [] . Numele si pozitia pot fi folosite intr-o expresie , cum ar fi : scorParticipant[40]=500; scorParticipant reprezinta o variabila care refera un obiect tablou . Pozitia ( indexul ) specifica locatia care va fi accesata in cadrul tabloului Numerotarea pozitiilor incepe de la 0 astfel incat un tablou cu 10 elemente poate fi accesat folosind pozitiile 0 – 9 . Toate pozitiile unui tablou sunt verificate daca se incadreaza in limitele tabloului asa cum s-au specificat la crearea tabloului . In Java este imposibil sa accesam sau sa atribuim o valoare unei pozitii a tabloului aflata in afara limitelor sale , problema care aparea in C de exemplu . String[] vorbitor=new String[10]; vorbitor[10] =”Text introdus”; Un program care foloseste aceste doua linii de cod va da eroare de compilare la folosirea variabilei vorbitor[10] . Eroarea apare din cauza ca tabloul nostru nu poseda pozitia a zecea . Pentru a evita in programe depasirea accidentala a sfarsitului tabloului putem folosi o variabila de instanta length – disponibila pentru toate obiectele tablou , indiferent de tip : int lungime=lungime.length; MODIFICAREA ELEMENTELOR TABLOURILOR Dupa cum am vazut mai sus putem atribui o valoare unei anumite pozitii a tabloului prin introducerea operatorului de atribuire dupa numele tabloului si al indexului : noteleMele[4]=10; propozitai[0]=”Aici”; propozitia[10]=propozitia[0]; Un lucru important de retinut este ca un tablou de obiecte , in Java , este un tablou de referinte la obiectele respective . Atunci cand atribuim o valoare unei pozitii dintr-un astfel de tablou nu se va
copia valoarea dintr-o pozitie in alta ci se va atribui referinta . In schimb , tablourile de tipuri de date primitive copiaza valorile dintr-o locatie in alta . Tablourile sunt relativ simplu de creat si modificat insa ofera foarte multe avantaje si sunt foarte utile in Java . 1: class TestTablou { 2: 3: String[] prenume={“Dennis”,”Grace”,”Bjarne”,”James”}; 4: String[] numeDeFamilie=new String[prenume.length]; 5: 6: void afiseazaNume() { 7: int i=0; 8: System.out.println(prenume[i] 9: +” “ +numeDeFamilie[i]); 10 i++; 11. System.out.println(prenume[i] 12: +” “ +numeDeFamilie[i]); 13 i++; 14. System.out.println(prenume[i] 15: +” “ +numeDeFamilie[i]); 16 i++; 17. System.out.println(prenume[i] 18: +” “ +numeDeFamilie[i]); 19 } 20: 21: public static void main (String argumente[]) { 22: TestTablou a=new TestTablou(); 23: a.afiseazNume(); 24: System.out.println(“____”); 25: a.numeDeFamilie[0]=”Ritchie”; 26: a.numeDeFamilie[1]=”Hopper”; 27: a.numeDeFamilie[2]=”Stroustrup”; 28: a.numeDeFamilie[3]=”Gosling”; 29: a.afiseazaNume(); 30: } 31: } In acest program cream o clasa TestTablou , cu doua variabile de instanta care pastreaza tablouri de obiecte String . Primul , prenume , este declarat si initializat in linia 3 pentru a contine patru siruri . A doua variabila , numeDeFamilie , este declarata si creata in linia 4 , insa nu contine nici o valoare initiala . Tabloul acesta are acelasi numar de pozitii ca si tabloul prenume , deoarece foloseste valoarea prenume.length . Atunci cand este folosita pentru un obiect tablou , variabila de instanta length intoarce numarul de pozitii din tablou . Clasa TestTablou mai contine si doua metode : afiseazaNume si main . Metoda afiseazaNume() , definita in liniile 6 – 19 , parcurge succesiv tablourile prenume si numeDeFamilie , afisand continutul fiecarei pozitii . Metoda main creaza o instanta initiala a clasei TestTablou ( in linia 22 ) asa incat sa I se poata folosi variabilele si metodele de instanta . Linia 23 apeleaza metoda afiseazaNume() , pentru a prezenta cum arata initial obiectul . Rezultatul este dat in primele patru linii afisate . Liniile 25 – 28 seteaza valorile fiecarei pozitii din tabloul numeDeFamilie . Linia 29 apeleaza inca o data metoda afiseazaNume() pentru a arata noile valori din tabloul numeDeFamilie .
TABLOURI MULTIDIMENSIONALE Dimensiunile multiple ale unui tablou sunt folositoare atunci cand reprezentam de exemplu un table x,y de elemente ale unui caroiaj . Java nu suporta tablourile multidimensionale , insa obtine acelasi efect prin declararea unui tablou de tablouri . Acele Tablouri pot contine si ele tablouri si asa mai departe , pana cand este obtinut numarul de dimensiuni dorit . Mai jos avem un exemplu de declarare si accesare a unor astfel de tablouri : int[][] coordonate=new int[12][12]; coordonate[0][0]=1; coordonate[0][1]=2; INSTRUCTIUNI BLOC Instructiunile din Java sunt grupate in blocuri . Inceputul si sfarsitul unui bloc sunt notate cu acolade {} . Blocurile sunt denumite si instructiuni bloc , deoarece un bloc poate fi folosit oriunde poate fi folosita o instructiune simpla . Fiecare instructiune din cadrul blocului se executa secvential . Blocurile pot fi plasate si in cadrul altor blocuri , asa cum se procedeaza la introducerea unei metode in cadrul unei definitii de clasa . Un lucru de retinut referitor la blocuri este acela ca ele creaza un domeniu de vizibilitate pentru variabilele locale create in cadrul blocului . Domeniu de vizibilitate este un termen folosit in programare pentru a denumi acea parte a programului in care o variabila exista si poate fi folosita . Daca programul paraseste domeniul de vizibilitate al unei variabile , aceasta nu mai exista si incercarea de a o accesa va da nastere unei erori . Domeniul de vizibilitate al unei variabile este blocul in care a fost creata . Atunci cand cream si folosim variabile locale in cadrul unui bloc , aceste variabile isi inceteaza existenta dupa ce blocul isi termina executia . void testBloc() { int x=10; { // incepere bloc int y=40; y=y+x; } // sfarsit bloc } In exemplul anterior exista doua variabile definite in cadrul acestei metode : x si y . Domeniul de vizibilitate al variabiley y este blocul in care se afla ; ea poate fi folosita doar in cadrul acestui bloc . Daca am incerca sa o folosim oriunde in alta parte a metodei testBloc() vom obtine o eroare . Variabila x a fost creata in interiorul metodei , insa in afara blocului interior , deci poate fi folosita in orice alta parte a metodei . Putem modifica valoarea lui x oriunde in cadrul metodei . INSTRUCTIUNEA CONDITIONALA IF Unul dintre aspectele cheie ale programarii este posibilitatea unui program de a decide ce va face . Acest lucru este tratat printr-un tip special de instructiuni denumite instructiuni conditionale . O instructiune conditionala reprezinta o instructiune executata doar in cazul indeplinirii unei anumite conditii . Cea mai des folosita instructiune conditionala este IF ( daca ) . Aceasta foloseste o expresie booleana pentru a decide daca o instructiune va fi sau nu executata . Daca expresia intoarce valoarea true instructiunea se va executa .
if (varsta>50) System.out.println(“Nu mai esti chiar tanar”); Daca dorim ca atunci cand expresia IF intoarce valoarea false sa se execute totusi ceva folosim cuvantul cheie optional else . if (alegere==true) restaurant=”President”; else restaurant=”Lido”; Expresia IF executa instructiuni diferite in functie de rezultatul unei singure testari booleene . OBS : Testul instructiunii IF in Java trebuie sa returneze o variabila booleana ( true sau false ) ; in C testul poate returna un intreg . In practica se foloseste si o versiune prescurtata a testului conditional IF ; in locul expresiei : if (alegere==true) Putem folosi doar : if (alegere) In continuare vom vedea un exemplu complet de aplicatie Java care se bazeaza pe folosirea testului IF : 1: class TestParitate { 2: 3: void verificareParitate(int val) { 4: System.out.println(“Valoarea este “ 5: +val+”. “); 6: if (val%2==0) 7: System.out.println(“Par”); 8: } 9: 10: public static void main (String argumente[]) { 11. TestParitate e=new TestParitate(); 12: 13: e.verificareParitate(1); 14: e.verificareParitate(2); 15: e.verificareParitate(54); 16: e.verificareParitate(77); 17: e.verificareParitate(1346); 18: } 19: } “Nucleul” clasei TestParitate este metoda verificareParitate() – liniile 3-8 – in care valorile sunt testate si se tipareste mesajul corespunzator . Metoda incepe prin tiparirea valorii care i-a fost transmisa . Argumentul este apoi testat folosind o instructiune conditionala IF , pentru a verifica daca un numar este par . Metoda main() a aplicatiei creaza o noua instanta a clasei TestParitate si o testeaza apeland metoda verificareParitate() de mai multe ori , cu diferite valori . OPERATORUL CONDITIONAL O alternativa viabila in practica este folosirea intr-o instructiune conditionala , in locul cuvintelor cheie IF si ELSE a operatorului conditional ( numit si operator ternar – deoarece are trei termeni ) .
Operatorul conditional este o expresie , ceea ce inseamna ca intoarce o valoare , spre deosebire de mai generalul IF care are ca rezultat doar executarea unei instructiuni . Operatorul conditional este mai util pentru instructiuni conditionale scurte sau simple , ca in exemplul urmator : test?rezultat_adevarat:rezultat_fals; test este o expresie care intoarce true sau false , la fel ca testul din instructiunea IF . Daca testul este adevarat ( true ) operatorul conditional intoarce valoarea rezultat_adevarat iar daca este fals returneaza rezultat_fals . Mai jos putem vedea un exemplu practic : int celMaiBunScor=scorulMeu>scorulTau?scorulMeu:scorulTau; Folosirea operatorului conditional este echivalentul urmatorului cod IF : int celMaiBunScor; if (scorulMeu>scorulTau) celMaiBunScor=scorulMeu; else celMaiBunScor=scorulTau; Operatorul conditional are o precedenta foarte scazuta – este de obicei evaluat dupa toate subexpresiile sale . Singurii operatori care au precedenta mai mica sunt cei de atribuire . INSTRUCTIUNEA SWITCH O operatie des intalnita in orice limbaj este compararea unei variabile cu o anumita valoare , apoi compararea cu o alta in caz ca nu se potriveste cu prima si asa mai departe . Acest proces poate deveni destul de dificil daca s-ar folosi doar instructiuni IF , in functie de diversitatea valorilor pe care trebuie sa le comparam . De exemplu putem ajunge la un set de instructiuni de genul : if (oper==’+’) adunaArg(arg1,arg2); else if (oper==’-‘) scadeArg(arg1,arg2); else if (oper==’*’) inmultireArg(arg1,arg2); else if (oper==’/’) imparteArg(arg1,arg2); Folosirea IF-ului in acest caz este o imbricare deoarece fiecare instructiune else contine o alta if pana se fac toate testele posibile . Un mecanism prescurtat pentru aceste instruciuni IF imbricate , care poate fi folosit in unele limbaje de programare , este gruparea testelor si actiunilor intr-o singura instructiune . In Java putem grupa actiunile – ca si in C – folosind instructiunea SWITCH . switch(nota) { case 10: System.out.println(“Foarte bine”); break; case 8: System.out.println(“Bine”);break; case 5: System.out.println(“Ai trecut”);break; default: System.out.println(“4 - ai cazut”); } Instructiunea SWITCH este bazata pe un test ; in exemplul nostru se testeaza variabila nota . Variabila testata , care poate fi de orice tip primitiv ( byte , short , char sau int ) este comparata pe rand cu fiecare dintre valorile case . Daca se gaseste o potrivire se executa instructiunea specificata dupa test ; daca nu se gaseste nici o potrivire se executa instructiunea default . Aceasta instructiune este de fapt optionala ; daca este omisa si nu se gaseste nici o potrivire case atunci instructiunea SWITCH se incheie fara a se executa nimic . Implementarea Java a instructiunii SWITCH este oarecum limitata – testele si valorile pot fi doar tipuri primitive simple ce pot fi convertite in int . Intr-o asemenea instructiune nu se pot folosi tipuri primitive de dimensiuni mai mari – large sau float – siruri sau alte obiecte si nici nu se pot testa alte relatii in afara de cea de egalitate . Aceste restrictii limiteaza folosirea SWITCH la cazuri relativ simple . In schimb instructiunile IF imbricate pot fi folosite pentru orice tip de testare .
Trebuie sa mentionez ca dupa o instructiune case putem include oricate instructiuni fara a fi necesare acoladele ( ca in cazul lui IF ) . Instructiunea break forteaza iesirea din instructiunea SWITCH la gasirea unei potriviri de valoare . Exista posibilitatea nefolosirii acestei instructiuni – caz in care programul executa mai departe instructiunile pana intalneste un break sau pana la sfarsitul instructiunii switch . Instructiunea break intrerupe executia in punctul curent si face un salt la codul aflat dincolo de urmatoarea acolada inchisa } . Avantajul nefolosirii lui break apare atunci cand se doreste executarea acelorasi instructiuni pentru mai multe valori . Pentru aceasta se folosesc mai multe linii case fara instructiuni ; astfel , switch va executa primele instructiuni pe care le va intalni . De exemplu , in urmatoarea instructiune switch sirul ‘x este un numar par’ este afisat doar daca x are una dintre valorile 2 , 4, 6 sau 8 . Toate celelalte valori ale lui x duc la afisarea textului default : switch(x) { case 2: case 4: case 6: case 8: system.out.println(“x este un numar par”); break; default: System.out.println(“x nu este par”); } In cele ce urmeaza vom detalia inca un exemplu care foloseste instructiunea SWITCH . Aceasta clasa converteste valorile intregi in cuvintele ce le denumesc . class CititorNumere{ String conversieNumar(int val) { switch (val) { case 0: return “zero”; case 1: return “unu”; case 2: return “doi”; case 3: return “trei”; case 4: return “patru”; case 5: return “cinci”; case 6: return “sase”; case 7: return “sapte”; case 8: return “opt”; case 9: return “noua”; default: return “ “; } } public static void main(String argumente[]) { CititorNumere n=new CititorNumere(); String num=n.conversieNumar(4)+n.conversieNumar(1)+n.conversieNumar(3); System.out.printl(“413 este convertit in : “+num); } } Instructiunea switch preia un argument intreg care este transmis metodei conversieNumar() care , daca gaseste o potrivire , intoarce valoarea corespunzatoare sub forma de sir . Nu este nevoie de instructiuni break in CititorNumere deoarece se foloseste in schimb instructiunea return . Aceasta este asemanatoare cu break , deosebirea fiind ca return iese definitiv din metoda si returneaza o valoare .
CICLURI FOR Ciclurile for repeta o instructiune de un numar specificat de ori , pana in momentul cand se intalneste o conditie . Chiar daca sunt folosite de obicei pentru simple iteratii , in care o instructiune este repetata de un numar de ori , ciclurile for pot fi folosite pentru orice tip de operatii repetitive . Ciclul for arata in Java ca mai jos : for ( initializare; test; incrementare) { instructiune; } Inceputul ciclului for contine trei parti : -
-
initializare este o expresie care initializeaza pornirea ciclului . Daca folosim o variabila index a ciclului aceasta expresie o poate declara si initializa in acelasi timp . Variabilele declarate in for sunt locale ciclului in sine . In acesta sectiune se pot initializa mai multe variabile , separand fiecare expresie printr-o virgula . test este testul care se face dupa fiecare parcurgere a ciclului . Testul trebuie sa fie o expresie booleana sau o functie care returneaza o valoare booleana , cum ar fi i<10 . Daca testul este true ciclul isi continua executia . O data intoarsa valoarea false ciclul isi intrerupe executia . incrementarea este o expresie sau un apel de functie . De obicei incrementarea este folosita pentru a modifica valoarea indexului ciclului , pentru a aduce starea ciclului mai aproape de final . Asemanator sectiunii initializare , putem specifica aici mai multe expresii , separate prin virgule .
In exemplul de mai jos putem vedea o instructiune for care atribuie tuturor pozitiilor unui tablou String valoarea Dl. : String[] formulSalut=new String[10]; int i; for (i=0;i
In exemplul anterior conditia care insoteste cuvantul cheie while este o expresie booleana , i<10 . Daca expresia returneaza true ciclul executa corpul sau si apoi testeaza din nou conditia . Acest proces se repeta pana cand conditia ia valoarea false . class CopieTablouWhile { public static void main (String argumente[]) { int[] tablou1={7,4,8,1,4,1,4}; float[] tablou2=new float[tablou1.length]; System.out.print(“tablou1 : [“); for (int i=0; i
cicluri executia continua cu urmatoarea iteratie a ciclului din exterior . Astfel , programul continua executia urmatoarei instructiuni aflata dupa ciclu . Sa revenim la exemplul ciclului while care copia elementele unui tablou de intregi intr-un tablou de numere in virgula mobila pana cand se intalnea valoarea 1 . Putem testa aceasta conditie in cadrul corpului ciclului while , dupa care folosim instructiunea break pentru a parasi ciclul : int index=0; while (index400) break afara; // ciclu interior } // ciclu exterior } In acest exemplu de cod , eticheta afara marcheaza ciclul exterior . In cadrul ciclurilor for si while , atunci cand este indeplinita o anumita conditie , instructiunea break cu eticheta are ca rezultat terminarea ambelor bucle . Fara folosirea etichetei afara , instructiunea break ar fi terminat executia ciclului interior si ar fi continuat executia cu cel exterior .