cursjava-algoritmica si programare-daniel danciu, silviu dumitrescu (bv 2002).pdf

182
Daniel DANCIU Silviu DUMITRESCU ALGORITMIC ˘ AS ¸I PROGRAMARE Curs ¸ si probleme de seminar JAVA Bra¸ sov 2002

Upload: mavinil

Post on 11-Nov-2015

50 views

Category:

Documents


12 download

TRANSCRIPT

  • Daniel DANCIU Silviu DUMITRESCU

    ALGORITMICA SI PROGRAMARECurs si probleme de seminar

    JAVA

    Brasov 2002

  • Cuprins

    1 Instalarea mediului Java 61.1 Obtinerea mediului Java pentru platforma dumneavoastra . . . . . . . . . . 6

    1.1.1 Medii de dezvoltare integrata . . . . . . . . . . . . . . . . . . . . . . 61.2 Instalarea mediului Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

    1.2.1 Instructiuni de instalare pentru Windows . . . . . . . . . . . . . . . 71.2.2 Instructiuni de instalare pentru Linux/Unix . . . . . . . . . . . . . . 7

    2 Notiuni fundamentale de programare in Java 92.1 Mediul de lucru Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92.2 Primul program Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

    2.2.1 Comentarii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102.2.2 Functia main . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102.2.3 Scrierea pe ecran . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

    2.3 Tipuri de date primitive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102.3.1 Tipurile primitive . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102.3.2 Constante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112.3.3 Declararea si initializarea tipurilor primitive n Java . . . . . . . . . 122.3.4 Citire/scriere de la terminal . . . . . . . . . . . . . . . . . . . . . . . 12

    2.4 Operatori de baza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122.4.1 Operatori de atribuire . . . . . . . . . . . . . . . . . . . . . . . . . . 132.4.2 Operatori aritmetici binari . . . . . . . . . . . . . . . . . . . . . . . 142.4.3 Operatori aritmetici unari . . . . . . . . . . . . . . . . . . . . . . . . 142.4.4 Conversii de tip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

    2.5 Instructiuni conditionale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152.5.1 Operatori relationali . . . . . . . . . . . . . . . . . . . . . . . . . . . 152.5.2 Operatori logici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152.5.3 Instructiunea if . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162.5.4 Instructiunea while . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182.5.5 Instructiunea for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182.5.6 Instructiunea do . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192.5.7 Instructiunile break si continue . . . . . . . . . . . . . . . . . . . . . 202.5.8 Instructiunea switch . . . . . . . . . . . . . . . . . . . . . . . . . . . 212.5.9 Operatorul conditional . . . . . . . . . . . . . . . . . . . . . . . . . . 22

    2.6 Metode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232.6.1 Suprancarcarea numelor la metode . . . . . . . . . . . . . . . . . . . 23

    2

  • CUPRINS 3

    2.7 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

    3 Referinte 253.1 Ce este o referinta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253.2 Fundamente despre obiecte si referinte . . . . . . . . . . . . . . . . . . . . . 27

    3.2.1 Operatorul punct (.) . . . . . . . . . . . . . . . . . . . . . . . . . . . 273.2.2 Declararea obiectelor . . . . . . . . . . . . . . . . . . . . . . . . . . . 273.2.3 Colectarea de gunoaie (garbage collection) . . . . . . . . . . . . . . . 283.2.4 Semnificatia lui = . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283.2.5 Transmiterea de parametri . . . . . . . . . . . . . . . . . . . . . . . 293.2.6 Semnificatia lui == . . . . . . . . . . . . . . . . . . . . . . . . . . . 303.2.7 Suprancarcarea operatorilor pentru obiecte . . . . . . . . . . . . . . 30

    3.3 Siruri de caractere (stringuri) . . . . . . . . . . . . . . . . . . . . . . . . . . 303.3.1 Fundamentele utilizarii stringurilor . . . . . . . . . . . . . . . . . . . 303.3.2 Concatenarea stringurilor . . . . . . . . . . . . . . . . . . . . . . . . 313.3.3 Comparatia stringurilor . . . . . . . . . . . . . . . . . . . . . . . . . 323.3.4 Alte metode pentru stringuri . . . . . . . . . . . . . . . . . . . . . . 323.3.5 Conversia de la string la tipurile primitive . . . . . . . . . . . . . . . 32

    3.4 Siruri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333.4.1 Declaratie, Atribuire si Metode . . . . . . . . . . . . . . . . . . . . . 333.4.2 Expansiunea dinamica a sirurilor . . . . . . . . . . . . . . . . . . . . 353.4.3 Siruri cu mai multe dimensiuni . . . . . . . . . . . . . . . . . . . . . 383.4.4 Argumente n linie de comanda . . . . . . . . . . . . . . . . . . . . 38

    3.5 Tratarea exceptiilor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393.5.1 Procesarea exceptiilor . . . . . . . . . . . . . . . . . . . . . . . . . . 393.5.2 Exceptii uzuale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41

    3.6 Intrare si iesire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423.6.1 Operatii de baza pe fluxuri (stream-uri) . . . . . . . . . . . . . . . . 423.6.2 Obiectul StringTokenizer . . . . . . . . . . . . . . . . . . . . . . . . 433.6.3 Fisiere secventiale . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44

    3.7 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

    4 Obiecte si clase 474.1 Ce este programarea orientata pe obiecte? . . . . . . . . . . . . . . . . . . . 474.2 Un exemplu simplu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 484.3 Metode uzuale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50

    4.3.1 Constructori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 504.3.2 Modificatori si Accesori . . . . . . . . . . . . . . . . . . . . . . . . . 524.3.3 Afisare si toString . . . . . . . . . . . . . . . . . . . . . . . . . . . . 524.3.4 Metoda equals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534.3.5 Variabile si metode statice . . . . . . . . . . . . . . . . . . . . . . . . 534.3.6 Metoda main . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

    4.4 Pachete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534.4.1 Directiva import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 544.4.2 Instructiunea package . . . . . . . . . . . . . . . . . . . . . . . . . . 554.4.3 Variabila sistem CLASSPATH . . . . . . . . . . . . . . . . . . . . . 55

  • 4 CUPRINS

    4.4.4 Reguli de vizibilitate Package-Friendly . . . . . . . . . . . . . . . . . 564.4.5 Compilarea separata . . . . . . . . . . . . . . . . . . . . . . . . . . . 56

    4.5 Alte operatii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 564.5.1 Referinta this . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 564.5.2 Prescurtarea this pentru constructori . . . . . . . . . . . . . . . . . . 574.5.3 Operatorul instanceof . . . . . . . . . . . . . . . . . . . . . . . . . . 584.5.4 Atribute statice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 584.5.5 Initializatori statici . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

    4.6 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

    5 Mostenire 685.1 Ce este mostenirea? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 685.2 Sintaxa de baza Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

    5.2.1 Reguli de vizibilitate . . . . . . . . . . . . . . . . . . . . . . . . . . . 715.2.2 Constructor si super . . . . . . . . . . . . . . . . . . . . . . . . . . . 725.2.3 Metode si clase final . . . . . . . . . . . . . . . . . . . . . . . . . . . 725.2.4 Redefinirea unei metode . . . . . . . . . . . . . . . . . . . . . . . . . 735.2.5 Metode si clase abstracte . . . . . . . . . . . . . . . . . . . . . . . . 74

    5.3 Exemplu: Extinderea clasei Shape . . . . . . . . . . . . . . . . . . . . . . . 765.4 Mostenire multipla . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 815.5 Interfete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81

    5.5.1 Definirea unei interfete . . . . . . . . . . . . . . . . . . . . . . . . . . 825.5.2 Implementarea unei interfete . . . . . . . . . . . . . . . . . . . . . . 825.5.3 Interfete multiple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83

    5.6 Implementarea de componente generice . . . . . . . . . . . . . . . . . . . . 845.7 Anexa - clasa Reader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 875.8 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88

    6 Analiza eficientei algoritmilor 906.1 Ce este analiza algoritmilor? . . . . . . . . . . . . . . . . . . . . . . . . . . 906.2 Notatia asimptotica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92

    6.2.1 O notatie pentru ordinul de marime al timpului de executie al unuialgoritm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92

    6.3 Tehnici de analiza algoritmilor . . . . . . . . . . . . . . . . . . . . . . . . . 946.3.1 Sortarea prin selectie . . . . . . . . . . . . . . . . . . . . . . . . . . . 946.3.2 Sortarea prin insertie . . . . . . . . . . . . . . . . . . . . . . . . . . . 956.3.3 Turnurile din Hanoi . . . . . . . . . . . . . . . . . . . . . . . . . . . 96

    6.4 Analiza algoritmilor recursivi . . . . . . . . . . . . . . . . . . . . . . . . . . 976.4.1 Metoda iteratiei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 976.4.2 Inductia constructiva . . . . . . . . . . . . . . . . . . . . . . . . . . 976.4.3 Recurente liniare omogene . . . . . . . . . . . . . . . . . . . . . . . . 986.4.4 Recurente liniare neomogene . . . . . . . . . . . . . . . . . . . . . . 1006.4.5 Schimbarea variabilei . . . . . . . . . . . . . . . . . . . . . . . . . . . 101

    6.5 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103

  • CUPRINS 5

    7 Structuri de date 1077.1 De ce avem nevoie de structuri de date? . . . . . . . . . . . . . . . . . . . . 1077.2 Stive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1097.3 Cozi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1117.4 Liste nlantuite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1137.5 Arbori binari de cautare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1177.6 Tabele de repartizare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1217.7 Cozi de prioritate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1237.8 Aplicatie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124

    8 Metoda Backtracking 1298.1 Prezentare generala . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1298.2 Prezentarea metodei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130

    8.2.1 Atribuie si avanseaza . . . . . . . . . . . . . . . . . . . . . . . . . . . 1338.2.2 Incercare esuata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1338.2.3 Revenire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1348.2.4 Revenire dupa construirea unei solutii . . . . . . . . . . . . . . . . . 134

    8.3 Implementarea metodei backtracking . . . . . . . . . . . . . . . . . . . . . . 1358.4 Probleme clasice care admit rezolvare prin metoda backtracking . . . . . . . 137

    8.4.1 Problema generarii permutarilor . . . . . . . . . . . . . . . . . . . . 1378.4.2 Generarea aranjamentelor si a combinarilor . . . . . . . . . . . . . . 1388.4.3 Problema damelor . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1408.4.4 Problema colorarii hartilor . . . . . . . . . . . . . . . . . . . . . . . 141

    8.5 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143

    9 Divide et Impera 1539.1 Notiuni elementare referitoare la recursivitate . . . . . . . . . . . . . . . . . 153

    9.1.1 Functii recursive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1539.1.2 Recursivitatea nu nseamna recurenta . . . . . . . . . . . . . . . . . 157

    9.2 Prezentarea metodei Divide et Impera . . . . . . . . . . . . . . . . . . . . . 1599.3 Cautare binara . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1609.4 Sortarea prin interclasare (MergeSort) . . . . . . . . . . . . . . . . . . . . . 1619.5 Sortarea rapida (QuickSort) . . . . . . . . . . . . . . . . . . . . . . . . . . . 1629.6 Expresii aritmetice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1649.7 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167

    10 Algoritmi Greedy 17210.1 Problema spectacolelor (selectarea activitatilor) . . . . . . . . . . . . . . . . 172

    10.1.1 Demonstrarea corectitudinii algoritmului . . . . . . . . . . . . . . . . 17310.2 Elemente ale strategiei Greedy . . . . . . . . . . . . . . . . . . . . . . . . . 174

    10.2.1 Proprietatea de alegere Greedy . . . . . . . . . . . . . . . . . . . . . 17610.2.2 Substructura optima . . . . . . . . . . . . . . . . . . . . . . . . . . . 177

    10.3 Minimizarea timpului mediu de asteptare . . . . . . . . . . . . . . . . . . . 17710.4 Interclasarea optima a mai multor siruri ordonate . . . . . . . . . . . . . . 17810.5 Probleme propuse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181

  • Capitolul 1

    Instalarea mediului Java

    In acest capitol, vom da cateva posibilitati de descarcare a softului, necesar pentru rulareaunor aplicatii Java, de pe Internet precum si instalarea acestuia.

    1.1 Obtinerea mediului Java pentru platforma dumneav-oastra

    Mediul de baza Java consta dintr-un browser web unde puteti vizualiza applet-urile Java,un compilator Java ce transforma codul sursa Java n cod binar si un interpretor pentrurularea programelor Java. Aveti nevoie de asemenea de un editor de texte ca emacs,TextPad sau BBEdit. Alte unelte ca debugger, un mediu vizual de dezvoltare etc. nu suntabsolut necesare.Nu este necesar sa luati toate partile de la aceeasi sursa. De obicei, browser-ul vostrude web va fi Internet Explorer sau Netscape. Celelalte le puteti obtine de la Suns JavaDeveloper Kit (JDK). Sun publica versiuni pentru toate platformele (Windows, Solaris,X86 Linux).JDK nu include un browser web dar contine un applet viewer pentru testarea applet-urilor.JDK include de asemenea compilatorul javac, interpretorul java, profiler-ul javaprof, gene-ratotul fisierelor C de tip header (pentru integrarea metodelor scrise n C ntr-o clasa Java)javah precum si depanatorul Java si generatorul de documentatie. Mai multa documentatiedespre JDK puteti gasi n pagina de web a firmei Sun.Sun furnizeaza masina virtuala Java pentru Solaris, X86 Linux si Wndows 95, 98, NT.Pentru aceasta lucrare aveti nevoie de Java 2 Software Development Kit, versiunea 1.2(JDK 1.2) sau urmatoarele. Versiunea JDK 1.3, utilizata si ea destul de des, nu estedisponibila pentru toate platformele. Totusi, diferentele ntre JDK1.2 si JDK1.3 nu suntfoarte importante.

    1.1.1 Medii de dezvoltare integrata

    Posibilitatile de dezvoltare integrata ale aplicatiilor Java sunt nca primitive n comparatiecu ceea ce este disponibil pentru C++. Se pare ca cel putin deocamdata mediile dedezvoltare integrata (IDE-Integrated Development Environments) nu sunt foarte perfor-mante. Acestea includ Metrowerks Code Warrior, Borland JBuilder, WinGate Visual Cafe

    6

  • 1.2. INSTALAREA MEDIULUI JAVA 7

    sau Microsoft Visual J++.

    1.2 Instalarea mediului Java

    Pentru nceput trebuie sa va descarcati JDK-ul pe care urmeaza apoi sa l instalati.

    1.2.1 Instructiuni de instalare pentru Windows

    Stergeti mai ntai toate variantele de JDK pe care le aveti deja instalate, mai ales dacadoriti sa puneti noul JDK ntr-un alt director. De asemenea, trebuie sa folositi regeditpentru a sterge toate cheile anterior instalate.Aveti nevoie de aproximativ 60 MB de spatiu de memorie liber pentru instalarea JDK-ului. Executati un dublu clic pe icoana din File Manager sau selectand Run... din meniulProgram Manager File editati calea catre fisier. Aceasta va poduce dezarhivarea incluzandtoate directoarele si subdirectoarele necesare. Vom presupune ca instalarea s-a facut nC:\jdk.Este necesar sa adaugati directotul C:\jdk\bin variabilei de mediu PATH. De exemplu:

    C:\>set PATH="c:\jdk\bin;$PATH"

    Acest lucru poate fi realizat permanent prin introducerea comenzii anterioare n fisierulautoexec.bat.Pentru a va asigura ca mediul vostru Java este corect configurat, deschideti o fereastraDOS si editati javac nofile.java. Astfel:

    C:\>javac nofile.java

    Daca primiti raspunsul:

    error: Cant read: nofile.java

    atunci instalarea a fost facuta cu succes. Daca primiti raspunsul:

    The name specified is not recognized as aninternal or external command, operable program or batch file.

    sau ceva similar atunci mediul Java nu a fost bine instalat sau variabila PATH nu are ovaloare corecta. Trebuie rezolvate aceste probleme nainte de a continua.

    1.2.2 Instructiuni de instalare pentru Linux/Unix

    Aveti nevoie de aproximativ 60 MB de spatiu de memorie liber pentru instalarea JDK-ului dar dublu ar fi de mare ajutor. Modul de dezarhivare dintr-un fisier gzipped tar esteurmatorul:

    % gunzip jk1_2_2-linux-i386.tar.gz% tar xvf jdk1_2_2-linux-i386.tar

  • 8 CAPITOLUL 1. INSTALAREA MEDIULUI JAVA

    Numele exact al fisierului poate fi un pic modificat daca folositi o platforma diferita ca siIrix sau o versiune diferita.Puteti face dezarhivarea n directorul curent sau daca aveti drepturi de root ntr-un altloc ca de exemplu /usr/local/java unde toti utilizatorii pot avea acces la fisiere. Oricumdrepturile de root nu sunt necesare pentru a instala Java.Dezarhivarea creaza toate directoarele si subdirectoarele necesare. Calea exacta nu esteimportanta, dar pentru simplitate vom presupune n continuare ca instalarea s-a facut n/usr/local/java. Veti gasi fisierele n /usr/local/java/jdk1.2.2. Daca dezarhivati o versiunediferita, atunci fisierele vor fi ntr-o cale usor modificata ca de exemplu /usr/local/java/jdk1.3.Este posibil ca mai multe versiuni de JDK sa coexiste armonios n acelasi sistem. Dacadezarhivati altundeva decat /usr/local/java trebuie sa nlocuiti /usr/local/java cu caleacompleta pana la directorul java. Daca instalati n directorul curent puteti folosi /javan loc de calea completa.Acum trebuie sa adaugati directorul /usr/local/java/jdk1.2.2/bin variabilei de mediu PATH.Acest lucru se poate face astfel dependent de shell-ul vostru:

    csh,tcsh:

    % set PATH=($PATH/usr/local/java/jdk1.2.2/bin)

    sh:

    % PATH=($PATH/usr/local/java/bin); export $PATH

    Puteti sa adaugati liniile anterioare la sfarsitul fisierelor .profile sau .cshrc pentru a nu lemai scrie la fiecare login-are.Pentru a va asigura ca mediul vostru Java este corect configurat, editati javac nofile.javala prompt-ul vostru shell:

    % javac nofile.java

    Daca primiti raspunsul:

    error: Cant read: nofile.java

    atunci instalarea a fost facuta cu succes. Daca primiti raspunsul:

    javac: Command not found

    sau ceva similar atunci mediul Java nu a fost bine instalat sau variabila PATH nu are ovaloare corecta. Trebuie rezolvate aceste probleme nainte de a continua.

  • Capitolul 2

    Notiuni fundamentale deprogramare in Java

    2.1 Mediul de lucru Java

    Codul sursa Java este continut n fisiere text care au extensia .java. Compilatorul local,care este de obicei javac sau jikes1, compileaza programul si genereaza fisiere .class carecontin byte-code. Byte-code este un limbaj intermediar portabil care este interpretat decatre interpretorul de Java, numit java.

    2.2 Primul program Java

    Sa ncepem prin a examina programul simplu din Figura 2.1. Acest program tiparesteun scurt mesaj pe ecran. Numerele din stanga fiecarei linii nu fac parte din program. Elesunt furnizate doar pentru o mai usoara referire a secventelor de cod.Transpuneti programul ntr-un fisier cu numele FirstProgram.java2 dupa care compilati-lsi rulati-l. Java este case-sensitive, ceea ce nseamna ca face deosebirile ntre literele marisi mici.

    1. //Primul program2. public class FirstProgram3. {4. public static void main(String[] args)5. {6. System.out.println("Primul meu program Java") ;7. }8. }

    Figura 2.1 Un prim program simplu

    1javac este compilatorul de la Sun, jikes este compilatorul de la IBM si este preferat de multi program-atori deoarece este mult mai rapid.

    2Atentie la literele mari si mici!

    9

  • 10 CAPITOLUL 2. NOTIUNI FUNDAMENTALE DE PROGRAMARE IN JAVA

    2.2.1 Comentarii

    In Java exista trei tipuri de comentarii. Prima forma, care este mostenita de la C ncepecu /* si se termina cu */. Iata un exemplu:

    1. /* Acesta este un comentariu2. pe doua linii */

    Comentariile nu pot fi imbricate, deci nu putem avea un comentariu n interiorul altuicomentariu.Cea de-a doua forma de comentarii este mostenita de la limbajul C++ si ncepe cu //.Nu exista simbol pentru ncheiere, deoarece un astfel de comentariu se extinde automatpana la sfarsitul liniei curente. Acest comentariu este folosit n linia 1 din Figura 2.1.Cea de-a treia forma este asemanatoare cu prima doar ca ncepe cu /** n loc de /*.Acesta forma de comentariu este utilizata pentru a furniza informatii utilitarului javadoc.Comentariile au fost introduse pentru a face codul mai lizibil pentru programatori. Unprogram bine comentat reprezinta un semn al unui bun programator.

    2.2.2 Functia main

    Un program Java consta dintr-o colectie de clase care interactioneaza ntre ele prin inter-mediul metodelor. Echivalentul Java al unei proceduri sau functii din Pascal sau C estemetoda statica, pe care o vom descrie mai pe larg n acest capitol. Atunci cand se executaun program Java, va fi invocata automat metoda statica main. Linia 4 din Figura 2.1arata ca metoda main poate fi eventual invocata cu anumiti parametri n linia de comanda.Tipul parametrilor functiei main cat si tipul functiei, void, sunt obligatorii.

    2.2.3 Scrierea pe ecran

    Programul din Figura 2.1 consta dintr-o singura instructiune, aflata la linia 6. Functiaprintln reprezinta principalul mecanism de scriere n Java, fiind echivalent ntr-o anumitamasura cu functia writeln din Pascal sau printf din C. In aceasta situatie se scrie un sirde caractere la fluxul de iesire standard System.out. Vom discuta despre citire/scriere maitarziu. Deocamdata ne multumim doar sa amintim ca aceeasi sintaxa este folosita pentrua scrie orice fel de entitate, fie ca este vorba despre un ntreg, real, sir de caractere sau alttip.

    2.3 Tipuri de date primitive

    Java defineste opt tipuri primitive de date, oferind de asemenea, o foarte mare flexibili-tate n a defini noi tipuri de date, numite clase. Totusi n Java, exista cateva diferenteestentiale ntre tipurile de date primitive si cele definite de utilizator. In aceasta sectiunevom examina tipurile primitive si operatiile fundamentale care pot fi realizate asupra lor.

    2.3.1 Tipurile primitive

    Java are opt tipuri de date primitive prezentate n Figura 2.2.

  • 2.3. TIPURI DE DATE PRIMITIVE 11

    Tip de data Ce retine Valoribyte ntreg pe 8 biti -128 la 127short ntreg pe 16 biti -32768 la 32767int ntreg pe 32 biti -2.147.483.648 la 2.147.483.647long ntreg pe 64 biti 263 la 263 1float virgula mobila pe 32 biti 6 cifre semnificative, (1046 la 1038)double virgula mobila pe 64 biti 15 cifre semnificative, (10324 la 10308)char caracter unicode

    boolean variabila booleana false si true

    Figura 2.2 Cele opt tipuri de date primitive n Java

    Cel mai des utilizat este tipul ntreg specificat prin cuvantul cheie int. Spre deosebirede majoritatea altor limbaje de programare, marja de valori a tipurilor ntregi nu estedependenta de masina. Java accepta si tipurile ntregi byte, short si long. Numerele reale(virgula mobila) sunt reprezentate de tipurile float si double. Tipul double are mai multecifre semnficative, de aceea utilizarea lui este recomandata n locul tipului float. Tipul chareste folosit pentru a reprezenta caractere. Un char ocupa 16 biti pentru a putea reprezentastandardul Unicode. Standardul Unicode contine peste 30.000 de caractere distincte careacopera principalele limbi scrise (inclusiv Japoneza, Chineza etc.). Prima parte a tabeleiUnicode este identica cu tabela ASCII. Ultimul tip primitiv este boolean; o variabila de tipboolean poate lua una din valorile true sau false.

    2.3.2 Constante

    Constantele ntregi pot fi reprezentate n bazele 10, 8 sau 16. Notatia octala este indi-cata printr-un 0 nesemnificativ la nceput; notatia hexa este indicata printr-un 0x sau 0Xla nceput. Iata cateva moduri echivalente de a reprezenta ntregul 37: 37, 045, 0x25.Notatiile octale si hexazecimale nu vor fi utilizate n acest curs. Totusi trebuie sa fimconstienti de ele pentru a folosi 0-uri la nceput doar acolo unde chiar vrem aceasta.O constanta caracter este cuprinsa ntre apostrofuri, cum ar fi a. Intern, Java inter-preteaza aceasta constanta ca pe un numar (codul Unicode). Ulterior, functiile de scrierevor transforma acest numar n caracterul corespunzator. Constantele caracter mai pot fireprezentate si n forma:

    \uxxxx.

    unde xxxx este un numar n baza 16 reprezentand codul Unicode al caracterului.Constantele de tip sir de caractere sunt cuprinse ntre ghilimele, ca n Primul meu programJava. Exista anumite secvente speciale, numite secvente escape, care sunt folosite pentruanumite caractere speciale. Noi vom folosi mai ales

    \n, \\, \ si \",

    care nseamna respectiv linie noua, backslash, apostrof si ghilimele.

  • 12 CAPITOLUL 2. NOTIUNI FUNDAMENTALE DE PROGRAMARE IN JAVA

    2.3.3 Declararea si initializarea tipurilor primitive n Java

    Orice variabila Java, inclusiv cele primitive, sunt declarate prin descrierea numelui a ti-pului si, optional, a valorii initiale. Numele variabilei trebuie sa fie un identificator. Unidentificator poate sa contina orice combinatie de litere, cifre si caracterul underscore(liniuta de subliniere). Identificatorii nu pot ncepe cu o cifra. Cuvintele rezervate, cum arfi int nu pot fi identificatori. Nu pot fi utilizati nici identificatorii care deja sunt declaratisi sunt vizibili.Java este case-sensitive, ceea ce nseamna ca sum si Sum reprezinta identificatori diferiti.In acest text vom folosi urmatoarea conventie pentru numele variabilelor:

    toate numele de variabila ncep cu litera mica, iar cuvintele noi din cadrul numeluincep cu litera mare. De exemplu: sumaMaxima, nodVizitat etc.

    numele claselor ncepe cu litera mare. De exemplu: FirstProgram, ArithmeticExcep-tion, BinaryTree etc.

    Alte conventii vor mai fi prezentate pe parcurs.Iata cateva exemple de declaratii de variabile:

    int numarElemente ;double mediaGenerala ;int produs = 1, suma = 0 ;int produs1 = produs ;

    O variabila este bine sa fie declarata imediat nainte de a fi folosita. Asa cum vom vedeamai tarziu, locul unde este declarata determina domeniul de vizibilitate si semnificatia ei.

    2.3.4 Citire/scriere de la terminal

    Scrierea la terminal n Java se realizeaza cu functia println si nu pune probleme ma-jore. Lucrurile nu stau deloc la fel cu citirea de la tastatura, care se realizeaza mult maianevoios. Acest lucru se datoreaza n primul rand faptului ca programele Java nu suntconcepute pentru a citi de la tastatura. In imensa majoritate a cazurilor programele Javasi preiau datele dintr-o interfata grafica (Applet-urile), din forme HTML (Java Servlets,Java Server Pages) sau din fisiere.Citirea si scrierea de la consola sunt realizate prin readLine, respectiv println. Fluxul deintrare standard este System.in iar fluxul de iesire standard este System.out.Mecanismul de baza pentru citirea/scrierea formatata foloseste tipul String, care va fi de-scris n capitolul urmator. La afisare, operatorul + concateneaza doua String-uri. Pentrutipurile primitive, daca parametrul scris nu este de tip String se face o conversie temporarala String. Aceste conversii pot fi definite si pentru obiecte, asa cum vom arata mai tarziu.Pentru citire se asociaza un obiect de tipul BufferedReader cu System.in. Apoi se citesteun String care va fi ulterior prelucrat.

    2.4 Operatori de baza

    Aceasta sectiune descrie operatorii de baza care sunt disponibili n Java. Acesti operatorisunt utilizati pentru a crea expresii. O constanta sau o variabila reprezinta o expresie,

  • 2.4. OPERATORI DE BAZA 13

    la fel ca si combinatiile de constante si variabile cu operatori. O expresie urmata de ;reprezinta o instructiune simpla. In paragraful 2.5 vom prezenta alte tipuri de instructiuni,care vor introduce noi tipuri de operatori.

    2.4.1 Operatori de atribuire

    Programul simplu din Figura 2.3 ilustreaza cativa operatori Java. Operatorul de atribuireeste semnul egal (=). De exemplu, n linia 16, variabilei a i se atribuie valoarea variabilei c(care n acel moment are valoarea 6). Modificarile ulterioare ale variabilei c nu vor afectavariabila a. Operatorii de atribuire pot fi nlantuiti ca n:

    z=y=x=0.

    Un alt operator de atribuire este += al carui mod de utilizare este ilustrat n linia 18.Operatorul += adauga valoarea aflata la dreapta (operatorului) la variabila din stanga.Astfel, valoarea lui c este incrementata de la 6 la 14. Java ofera si alti operatori de atribuirecum ar fi -=, *= si /= care modifica variabila aflata n partea stanga prin scadere, nmultiresi respectiv mpartire.

    1. public class OperatorTest2. {3. //program care ilustreaza operatorii de baza4. //programul va afisa:5. //12 8 66. //6 8 67. //6 8 148. //22 8 149. //24 10 3310.11. public static void main(String[] args)12. {13. int a = 12, b = 8, c = 6 ;14.15. System.out.println(a + " " + b + " " + c) ;16. a = c ;17. System.out.println(a + " " + b + " " + c) ;18. c += b ;19. System.out.println(a + " " + b + " " + c) ;20. a = b + c ;21. System.out.println(a + " " + b + " " + c) ;22. a++ ;23. ++b ;24. c = a++ + ++b ;25. System.out.println(a + " " + b + " " + c) ;26. }27.}

    Figura 2.3 Program care ilustreaza anumiti operatori simpli

  • 14 CAPITOLUL 2. NOTIUNI FUNDAMENTALE DE PROGRAMARE IN JAVA

    2.4.2 Operatori aritmetici binari

    Linia 20 din Figura 2.3 ilustreaza unul dintre operatorii binari care sunt tipici pentrulimbajele de programare: operatorul de adunare (+). Operatorul + are ca efect adunareacontinutului variabilelor b si c; valorile lui b si c raman neschimbate. Valoarea rezultataeste atribuita lui a. Alti operatori aritmetici folositi n Java sunt: -, *, / si % utilizatirespectiv pentru scadere, nmultire, mpartire si rest.Impartirea a doua valori ntregi are ca valoare doar partea ntrega a rezultatului. De e-xemplu 3/2 are valoarea 1, dar 3.0/2 are valoarea 1.5.Asa cum este si normal, adunarea si scaderea au aceeasi prioritate. Aceasta prioritateeste mai mica decat cea a grupului format din nmultire, mpartire si rest; astfel 1 + 2*3are valoarea 7. Toti acesti operatori sunt evaluati de la stanga la dreapta (astfel 3-2-2 arevaloarea -1). Toti operatorii aritmetici au o anumita prioritate si o anumita asociere.

    2.4.3 Operatori aritmetici unari

    In plus fata de operatorii aritmetici binari care necesita doi operanzi, Java dispune si deoperatori unari care necesita doar un singur operand. Cel mai cunoscut operator unareste operatorul minus (-) care returneaza operandul cu semn opus. Astfel, -x, este opusullui x.Java ofera de asemenea operatorul de autoincrementare care adauga 1 la valoarea uneivariabile, notat prin ++, si operatorul de autodecrementare care scade 1 din valoareavariabilei, notat cu - -. Un caz banal de utilizare a acestor operatori este exemplificatn liniile 22 si 23 din Figura 2.3. In ambele cazuri operatorul ++ adauga 1 la valoareavariabilei. In Java, ca si n C, orice expresie are o valoare. Astfel, un operator aplicatunei variabile genereaza o expresie cu o anumita valoare. Desi faptul ca variabila esteincrementata nainte de executia urmatoarei instructiuni este garantat, se pune ntrebarea:Care este valoarea expresiei de autoincrementare daca ea este utilizata n cadrul unei alteexpresii?In acest caz, locul unde se plaseaza operatorul ++ este esential. Semnficatia lui ++xeste ca valoarea expresiei este egala cu noua valoare a lui x. Acest operator este numitincrementare prefixata. In mod analog, x++ nseamna ca valoarea expresiei este egala cuvaloarea originala a lui x. Acesta este numit incrementare postfixata. Aceste trasaturisunt exemplificate n linia 24 din Figura 2.3. Atat a, cat si b sunt incrementate cu 1, iarc este obtinut prin adunarea valorii initiale a lui a (care este 23) cu valoarea incrementataa lui b (care este 10).

    2.4.4 Conversii de tip

    Operatorul conversie de tip, numit adeseori si operatorul de cast, este utilizat pentru agenera o variabila temporara de un nou tip. Sa consideram, de exemplu, secventa de cod:

    double rest ;int x = 6 ;int y = 10 ;rest = x / y ; //mai mult ca sigur gresit!

  • 2.5. INSTRUCTIUNI CONDITIONALE 15

    La efectuarea operatiei de mpartire, atat x cat si y fiind numere ntregi, se va realiza ompartire ntreaga si se obtine 0. Intregul 0 este apoi convertit implicit la double astfelncat sa poata fi atribuit lui rest. Probabil ca intentia noastra era aceea de a atribui luirest valoarea 0.6. Solutia este de a converti temporar pe x sau pe y la double, pentru campartirea sa se realizeze n virgula mobila. Acest lucru se poate obtine astfel:

    rest = ( double ) x / y ;

    De remarcat ca nici x si nici y nu se schimba. Se creaza o variabila temporara fara nume,avand valoarea 6.0, iar valoarea ei este utilizata pentru a efectua mpartirea. Operatorulde conversie de tip are o prioritate mai mare decat operatorul de mpartire, de aceeaconversia de tip se efectueaza nainte de a se efectua mpartirea.

    2.5 Instructiuni conditionale

    Aceasta sectiune este dedicata instructiunilor care controleaza fluxul de executie al pro-gramului: instructiunile conditionale si iteratia.

    2.5.1 Operatori relationali

    Testul fundamental care poate fi realizat asupra tipurilor primitive este comparatia. Com-paratia se realizeaza utilizand operatorii de egalitate/inegalitate si operatorii de comparatie( etc.). In Java, operatorii de egalitate/inegalitate sunt == respectiv !=. De exemplu,

    exprStanga == exprDreapta

    are valoarea true daca exprStanga si exprDreapta sunt egale; altfel are valoarea false.Analog, expresia:

    exprStanga != exprDreapta

    are valoarea true daca exprStanga si exprDreapta sunt diferite; altfel are valoarea false.Operatorii de comparatie sunt = iar semnficatia lor este cea naturala pentrutipurile fundamentale. Operatorii de comparatie au prioritate mai mare decat operatoriide egalitate. Totusi, ambele categorii au prioritate mai mica decat operatorii aritmetici,dar mai mare decat operatorii de atribuire. Astfel, veti constata adeseori ca folosireaparantezelor nu va fi necesara. Toti acesti operatori se asociaza de la stanga la dreapta,dar cunoasterea acestui lucru nu ne foloseste prea mult. De exemplu, n expresia a < b < 6,prima comparatie genereaza o valoare booleana, iar a doua expresie este gresita, deoareceoperatorul < nu este definit pentru valori booleene. Paragraful urmator descrie cum sepoate realiza acest test n mod corect.

    2.5.2 Operatori logici

    Java dispune de operatori logici care sunt utilizati pentru a simula operatorii and, orsi not din algebra Booleana. Acesti operatori mai sunt referiti uneori si sub numele deconjunctie, disjunctie si, respectiv, negare, simbolurile corespunzatoare fiind &&, || si !.Implementarea corecta a testului din paragraful anterior este:

  • 16 CAPITOLUL 2. NOTIUNI FUNDAMENTALE DE PROGRAMARE IN JAVA

    a>> Stanga la dreapta

    Relationali < >= instanceof Stanga la dreaptaEgalitate == ! = Stanga la dreapta

    AND pe biti & Stanga la dreaptaXOR pe biti Stanga la dreaptaOR pe biti | Stanga la dreaptaAND logic && Stanga la dreaptaOR logic || Stanga la dreapta

    Conditional ? : Dreapta la stangaAtribuire = = / = % = + = = Dreapta la stanga

    Figura 2.4 Operatori Java listati n ordinea prioritatii3

    O regula importanta este ca operatorii && si || folosesc evaluarea booleana scurtcircuitata4.Aceasta nseamna ca daca rezultatul poate fi determinat evaluand prima expresie, a douanu mai este evaluata. De exemplu, n expresia:

    x !=0 && 1/x != 3

    daca x este 0, atunci prima jumatate este false. Aceasta nsemna ca rezultatul conjunctieiva fi fals, deci a doua expresie nu mai este evaluata. Acesta este un detaliu important,deoarece mpartirea la 0 ar genera un comportament eronat.

    2.5.3 Instructiunea if

    Instructiunea if este instructiunea fundamentala de decizie. Forma sa simpla este:

    if( expresie )instructiuneurmatoarea instructiune

    Daca expresie are valoarea true atunci se executa instructiune; n caz contrar instructiunenu se executa. Dupa ce instructiunea if se ncheie (fara o exceptie netratata), controluleste preluat de urmatoarea instructiune.Optional, putem folosi instructiunea if-else dupa cum urmeaza:

    3Prin asociere ntelegem odinea de evaluare ntr-o expresie care contine operatori de acelasi tip si nuare paranteze.

    4Numita uneori si evaluare booleana partiala

  • 2.5. INSTRUCTIUNI CONDITIONALE 17

    if( expresie )instructiune1elseinstructiune2urmatoarea instructiune

    In acest caz, daca expresie are valoarea true, atunci se executa instructiune1; altfel seexecuta instructiune2. In ambele cazuri controlul este apoi preluat de urmatoarea instruc-tiune. Iata un exemplu:

    System.out.println("1/x este") ;if( x != 0 )System.out.print( 1/x ) ;elseSystem.out.print( "Nedefinit" ) ;System.out.println() ;

    De retinut ca doar o singura instructiune poate exista pe ramura de if sau de else indiferentde cum indentati codul. Iata doua erori frecvente la ncepatori:

    if( x == 0 ) ; //instructiune vida!!!System.out.println( "x este 0" ) ;elseSystem.out.print( "x este" ) ;System.out.println(x) ; // a doua instructiune nu

    // face parte din else

    Prima gresala consta n a pune ; dupa if. Simbolul ; reprezinta n sine instructiunea vida;ca o consecinta, acest fragment de cod nu va fi compilabil (else nu va fi asociat cu niciun if). Dupa ce am corectat aceasta eroare, ramanem cu o eroare de logica: ultima liniede cod nu face parte din if, desi acest lucru este sugerat de indentare. Pentru a rezolvaaceasta problema vom utiliza un bloc n care grupam o secventa de instructiuni printr-opereche de acolade:

    if( x == 0 ){System.out.println( "x este 0" ) ;}else{System.out.print( "x este" ) ;System.out.println( x ) ;}

    Observati ca am folosit acolade si pe ramura de if desi acestea nu sunt absolut necesare.Aceasta practica mbunatateste foarte mult lizibilitatea codului si va invitam si pe dum-neavoastra sa o adoptati.Instructiunea if poate sa faca parte dintr-o alta instructiune if sau else, la fel ca si celelalteinstructiuni de control prezentate n continuare n aceasta sectiune.

  • 18 CAPITOLUL 2. NOTIUNI FUNDAMENTALE DE PROGRAMARE IN JAVA

    2.5.4 Instructiunea while

    Java, ca si Pascal sau C, dispune de trei instructiuni de ciclare: instructiunea while,instructiunea do si instructiunea for. Sintaxa instructiunii while este:

    while( expresie )instructiune

    urmatoarea instructiune

    Observati ca, la fel ca si la instructiunea if, nu exista ; n sintaxa. Daca apare un ; , dupawhile, va fi considerat ca instructiune vida.Cat timp expresie este true se executa instructiune; apoi expresie este evaluata din nou.Daca expresie este false de la bun nceput, atunci instructiune nu va fi executata niciodata.In general, instructiune face o actiune care ar putea modifica valoarea lui expresie; ncaz contrar, ciclarea s-ar putea produce la infinit. Cand instructiunea while se ncheie,controlul este preluat de urmatoarea instructiune.

    2.5.5 Instructiunea for

    Instructiunea while ar fi suficienta pentru a exprima orice fel de ciclare. Totusi, Javamai ofera nca doua forme de a realiza ciclarea: instructiunea for si instructiunea do.Instructiunea for este utilizata n primul rand pentru a realiza iteratia. Sintaxa ei este:

    for( initializare; test; actualizare)instructiune

    urmatoarea instructiune

    In aceasta situatie, initializare, test si actualizare sunt toate expresii, si toate trei suntoptionale. Daca test lipseste, valoarea sa implicita este true. Dupa paranteza de nchiderenu se pune ;.Instructiunea for se executa realizand mai ntai initializare. Apoi, cat timp test estetrue, au loc urmatoarele doua instructiuni: se executa instructiune, iar apoi se executaactualizare. Daca initializare si actualizare sunt omise, instructiunea for se va comportaexact ca si instructiunea while.Avantajul instructiunii for consta n faptul ca se poate vedea clar marja pe care itereazavariabilele contor.Urmatoarea secventa de cod afiseaza primele 100 numere ntregi pozitive:

    for( int i=1; i

  • 2.5. INSTRUCTIUNI CONDITIONALE 19

    for( i = 0, sum = 0; i

  • 20 CAPITOLUL 2. NOTIUNI FUNDAMENTALE DE PROGRAMARE IN JAVA

    2.5.7 Instructiunile break si continue

    Instructiunile for si while au conditia de terminare naintea instructiunilor care se repeta.Instructiunea do are conditia de terminare dupa instructiunile care se repeta. Totusi, nanumite situatii, s-ar putea sa fie nevoie sa ntrerupem ciclul n mijlocul instructiunilorcare se repeta. In acest scop, se poate folosi instructiunea break. De obicei, instructiuneabreak apare n cadrul unei instructiuni if, ca n exemplul de mai jos:

    while(...){...if( conditie ){break ;}...

    }

    In cazul n care sunt doua cicluri imbricate, instructiunea break paraseste doar ciclul celmai din interior. Daca exista mai mult de un ciclu care trebuie terminat, break nu vafunctiona corect, si mai mult ca sigur ca ati proiectat prost algoritmul. Totusi, Java oferaasa numitul break etichetat. In acest caz, o anumita instructiune de ciclare este etichetatasi instructiunea break poate fi aplicata acelei instructiuni de ciclare, indiferent de numarulde cicluri imbricate. Iata un exemplu:

    eticheta:while(...){while(...){...if( conditie ){break eticheta;}}}

    //controlul programului trece aici dupa executia lui break

    In anumite situatii dorim sa renuntam la executia iteratiei curente din ciclu si sa trecem laurmatoarea iteratie a ciclului. Acest lucru poate fi realizat cu instructiunea continue. Casi break, instructiunea continue este urmata de ; si se aplica doar ciclului cel mai interiorn cazul ciclurilor imbricate. Urmatorul fragment tipareste primele 100 de numere ntregi,cu exceptia celor divizibile cu 10:

    for( int i = 1 ; i

  • 2.5. INSTRUCTIUNI CONDITIONALE 21

    {continue ;}System.out.println( i ) ;}

    Desigur, ca exemplul de mai sus poate fi implementat si utilizand un if simplu. Totusiinstructiunea continue este adeseori folosita pentru a evita imbricari complicate de tipif-else n cadrul ciclurilor.

    2.5.8 Instructiunea switch

    Instructiunea switch este numita uneori si instructiune de selectie. Instructiunea switchselecteaza dintre mai multe secvente de cod, una care va fi executata, functie de valoareaunei expresii ntregi. Forma sa este:

    switch( expresie-selectare ){case valoare-intreaga1: instructiune ; break ;case valoare-intreaga2: instructiune ; break ;//...case valoare-intreagan: instructiune ; break ;default: instructiune ;}

    expresie-selectare este o expresie care produce o valoare ntreaga. Instructiunea switchcompara valoarea lui expresie-selectare cu fiecare valoare-intreaga. Daca are loc egalitatease executa instructiunea corespunzatoare (simpla sau compusa). Daca nu are loc nici oegalitate se executa instructiunea din default.Observati ca n exemplul de mai sus, fiecare case se ncheie cu un break care are ca efectsaltul la sfarsitul instructiunii switch. Acesta este modul obisnuit de a scrie o instructiunede tip switch, dar prezenta instructiunii break este optionala. Daca instructiunea breaklipseste, atunci se va executa si codul corespunzator instructiunilor case urmatoare panacand se ntalneste un break. Desi de obicei nu ne dorim un astfel de comportament, elpoate fi uneori util pentru programatorii experimentati.Programul de mai jos creaza litere aleator si determina daca acestea sunt vocale sauconsoane (n limba engleza):

    1. //VowelsAndConsonants.java2. // Program demonstrativ pentru instructiunea switch3. public class VowelsAndConsonants4. {5. public static void main(String[] args)6. {7. for(int i = 0; i < 100; i++)8. {9. char c = (char)(Math.random() * 26 + a);10. System.out.print(c + ": ");

  • 22 CAPITOLUL 2. NOTIUNI FUNDAMENTALE DE PROGRAMARE IN JAVA

    11. switch(c)12. {13. case a:14. case e:15. case i:16. case o:17. case u:18. System.out.println("vocala");19. break;20. case y:21. case w:22. System.out.println(23. "Uneori vocale "); //doar in limba engleza!!!24. break;25. default:26. System.out.println("consoana");27. } //switch28. } //for29. } //main30.} //class

    Figura 2.5 Instructiunea switch

    Functia Math.random() genereaza o valoare n intervalul [0,1). Prin nmultirea valoriireturnate de aceasta functie cu numarul de litere din alfabet (26 litere) se obtine un numarn intervalul [0,26). Adunarea cu prima litera (a, care are de fapt valoarea 97) are caefect transpunerea n intervalul [97,123). In final se foloseste operatorul de conversie detip pentru a trunchia numarul la o valoare din multimea 97,98,...,122, adica un cod ASCIIal unui caracter din alfabetul englez .

    2.5.9 Operatorul conditional

    Operatorul coditional este folosit ca o prescurtare pentru instructiuni simple de tipul if-else.Forma sa generala este:

    exprTest ? expresieDa : expresieNu ;

    Mai ntai se evalueaza exprTest urmata fie de expresieDa fie de expresieNu, rezultandastfel valoarea ntregii expresii. expresieDa este evaluata daca exprTest are valoarea true;n caz contrar se evalueaza expresieNu. Prioritatea operatorului conditional este chiardeasupra operatorilor de atribuire. Acest lucru permite omiterea parantezelor atunci candasignam rezultatul operatorului conditional unei variabile. Ca un exemplu, minimul adoua variabile poate fi calculat dupa cum urmeaza:

    valMin = x < y ? x : y ;

  • 2.6. METODE 23

    2.6 Metode

    Ceea ce n alte limbaje de programare numeam procedura sau functie, n Java este numitmetoda. O definitie mai exacta si completa a notiunii de metoda o vom da mai tarziu. Inacest paragraf prezentam doar cateva notiuni elementare pentru a putea scrie functii degenul celor din C sau Pascal pe care sa le folosim n cateva programe simple.Antetul unei metode consta dintr-un nume, o lista (eventual vida) de parametri si un tippentru valoarea returnata. Codul efectiv al metodei numit adeseori corpul metodei esteun bloc (o secventa de instructiuni cuprinsa ntre acolade). Definirea unei metode constan antet si corp. Un exemplu de metoda si de o functie main care o utilizeaza este dat nFigura 2.6.Prin prefixarea metodelor cu ajutorul cuvintelor cheie public static putem mima ntr-o oarecare masura functiile din Pascal si C. Desi aceasta tehnica este utila n anumitesituatii, ea nu trebuie utilizata n mod abuziv. Numele metodei este un identificator.Lista de parametri consta din 0 sau mai multi parametri formali, fiecare avand un tipprecizat. Cand o metoda este apelata, parametrii actuali sunt trecuti n parametrii for-mali utilizand atribuirea obisnuita. Aceasta nsemna ca tipurile primitive sunt transmiseutilizand exclusiv transmiterea prin valoare. Parametrii actuali nu vor putea fi modificatide catre functie. Definirile metodelor pot aparea n orice ordine.Instructiunea return este utilizata pentru a ntoarce o valoare catre codul apelant. Dacatipul functiei este void atunci nu se ntoarce nici o valoare si se foloseste

    return ;

    fara nici un parametru.

    1. public class Minim2. {3. public static void main( String[] args )4. {5. int a = 3 ;6. int b = 7 ;7. System.out.println( min(a,b) ) ;8. }9. //declaratia metodei min10. public static int min( int x, int y )11. {12. return x < y ? x : y ;13. }14.}

    Figura 2.6 Declararea si apelul unei metode

    2.6.1 Suprancarcarea numelor la metode

    Sa presupunem ca dorim sa scriem o metoda care calculeaza maximul a trei numere ntregi.Un antet pentru aceasta metoda ar fi:

    int max(int a, int b, int c)

  • 24 CAPITOLUL 2. NOTIUNI FUNDAMENTALE DE PROGRAMARE IN JAVA

    In unele limbaje de programare (Pascal, C), acest lucru nu ar fi permis daca exista dejao functie max cu doi parametri. De exemplu, se poate sa avem deja declarata o metodamax cu antetul:

    int max(int a, int b)

    Java permite suprancarcarea (engl. overloading) numelui metodelor. Aceasta nsemna camai multe metode pot fi declarate n cadrul aceleiasi clase atata timp cat semnaturile lor(adica lista de parametri) difera. Atunci cand se face un apel al metodei max compilatorulpoate usor sa deduca despre care metoda este vorba examinand lista parametrilor de apel.Se poate sa existe metode suprancarcate cu acelasi numar de parametri formali atatatimp cat cel putin unul din tipurile din lista de parametri este diferit.De retinut faptul ca tipul functiei nu face parte din semnatura ei. Aceasta nseamna canu putem avea doua metode n cadrul aceleiasi clase care sa difere doar prin tipul valoriireturnate. Metode din clase diferite pot avea acelasi nume, parametri si chiar tip returnat;despre aceasta vom discuta pe larg mai tarziu.

    2.7 Probleme propuse

    1. Scrieti o instuctiune while echivalenta cu ciclul for de mai jos. La ce ar putea fiutilizat un astfel de ciclu?

    for( ; ; )instructiune

    2. Scrieti un program care genereaza tabelele pentru nmultirea si adunarea numerelorcu o singura cifra.

    3. Scrieti doua metode statice. Prima sa returneze maximul a trei numere ntregi, adoua maximul a patru numere ntregi .

    4. Scrieti o metoda statica care primeste ca parametru un an si returneaza true dacaanul este bisect si false n caz contrar.

  • Capitolul 3

    Referinte

    In capitolul 1 am prezentat tipurile primitive din Java. Toate tipurile care nu sunt ntrecele opt primitive, inclusiv tipurile importante cum ar fi stringurile, sirurile si fisierele sunttipuri referinta.In acest capitol vom nvata:

    Ce este un tip referinta si ce este o variabila referinta Prin ce difera un tip referinta de un tip primitiv Exemple de tipuri referinta incluzand stringuri, siruri si fluxuri Cum sunt utilizate exceptiile pentru a semnala comportamentul gresit alunei secvente de cod

    3.1 Ce este o referinta

    In capitolul 1 am examinat cele opt tipuri primitive, mpreuna cu cateva operatii care potfi realizate pe aceste tipuri. Toate celelalte tipuri de date din Java sunt referinte. Ce estedeci o referinta? O variabila referinta n Java (numita adeseori simplu referinta) este ovariabila care retine adresa de memorie la care se afla un anumit obiect.

    point3*

    point1HHj

    point2*

    1000 (0,0)1024 (5,12)3200 point2 = 10243600 point1 = 10005124 point3 = 1000

    Figura 3.1 Ilustrarea unei referinte: Obiectul de tip Point stocat la adresa de memorie1000 este referit atat de catre point1 cat si de catre point3. Obiectul de tip Point stocat laadresa 1024 este referit de catre point2. Locatiile de memorie unde sunt retinute variabileleau fost alese arbitrar.

    Ca un exemplu, n Figura 3.1 exista doua obiecte de tipul Point1. Presupunem ca acesteobiecte au fost stocate la adresele de memorie 1000 si respectiv 1024. Pentru aceste doua

    1Care contin coordonatele unui punct din plan.

    25

  • 26 CAPITOLUL 3. REFERINTE

    obiecte am definit trei referinte, point1, point2 si point3. Atat point1 cat si point3 referaobiectul stocat la adresa 1000; point2 refera obiectul stocat la adresa 1024; aceasta nsemnaca atat point1 cat si point3 au valoarea 1000, iar point2 va avea valoarea 1024. Retinetica locatiile efective, cum ar fi 1000 si 1024, sunt atribuite de compilator la discretia sa(unde gaseste memorie libera). In consecinta, aceste valori nu sunt utile efectiv ca valorinumerice. Totusi, faptul ca point1 si point3 au aceeasi valoare este folositor: nseamnaca ele refera acelasi obiect. O referinta stocheaza ntotdeauna adresa la care un anumitobiect se afla, cu exceptia situatiei cand nu refera nici un obiect. In aceasta situatie vastoca referinta nula, notata cu null. Java nu permite referinte catre tipurile primitive.Exista doua mari tipuri de operatii care se pot aplica variabilelor referinta.

    1. Prima categorie permite examinarea si manipularea valorii referinta. De exemplu,daca modificam valoarea stocata n point1 (care este 1000), putem sa facem ca point1sa refere un alt obiect. Putem de asemenea compara point1 si point3 pentru a vedeadaca refera acelasi obiect.

    2. A doua categorie de operatii se aplica obiectului care este referit; am putea deexemplu examina sau modifica starea unuia dintre obiectele de tipul Point (amputea examina coordonatele x si y ale unui obiect de tipul Point).

    Inainte de a descrie ce se poate face cu ajutorul referintelor, sa descriem ce nu se poateface. Sa consideram expresia point1*point2. Deoarece valorile retinute de point1 si point2sunt respectiv 1000 si 1024, produsul lor ar fi 1024000. Totusi acest calcul este lipsit desens si nu ar putea avea nici o valoarea practica. Variabilele referinta retin adrese, si nupoate fi asociata nici o semnificatie logica nmultirii adreselor.Analog, point1++ nu are nici un sens n Java; ar sugera ca point1 - care are valoarea1000 - sa fie crescut la 1001, dar n acest caz nu ar mai referi un obiect valid. Multe altelimbaje de programare definesc notiunea de pointer care are un comportament similar cucel al unei variabile referinta. Totusi, pointerii n C sunt mult mai periculosi, deoareceeste permisa aritmetica pe adresele stocate. In plus, deoarece C permite pointeri si catretipurile fundamentale trebuie avut grija pentru a distinge ntre aritmetica pe adrese siaritmetica pe variabilele care sunt referite. Acest lucru se face prin dereferentierea explicitaa pointerului. In practica, pointerii limbajului C tind sa provoace numeroase erori greudetectabile, care uneori i pot face si pe programatorii experimentati sa planga de ciuda!In Java, singurele operatii care sunt permise asupra referintelor (cu o singura exceptiepentru Stringuri) sunt atribuirea via = si comparatia via == sau !=. De exemplu, prinatribuirea lui point3 a valorii lui point2, vom face ca point3 sa refere acelasi obiect pe care lrefera point2. Acum expresia point2 == point3 este adevarata, deoarece ambele referintestocheaza valoarea 1024 si refera deci acelasi obiect. point1 != point2 este de asemeneaadevarata, deoarece point1 si point2 refera acum obiecte distincte.Cealalta categorie de operatii se refera la obiectul care este referit. Exista doar trei actiunifundamentale care pot fi realizate:

    1. Aplicarea unei conversii de tip

    2. Accesul la un camp al obiectului sau apelul unei metode prin operatorul punct (.)

    3. Utilizarea operatorului instanceof pentru a verifica daca obiectul retinut are un an-umit tip.

  • 3.2. FUNDAMENTE DESPRE OBIECTE SI REFERINTE 27

    Sectiunea urmatoare ilustreaza mai detaliat operatiile pe referinte.

    3.2 Fundamente despre obiecte si referinte

    In Java un obiect este orice variabila de un tip ne-primitiv. Obiectele sunt tratate diferitfata de tipurile primitive. Variabilele de tipuri primitive sunt manipulate prin valoare,ceea ce nsemna ca valorile lor sunt retinute n acele variabile si sunt copiate dintr-o vari-abila primitiva n alta variabila primitiva n timpul instructiunii de atribuire. Dupa cumam aratat n sectiunea anterioara, variabilele referinta stocheaza referinte catre obiecte.Obiectul n sine este stocat undeva n memorie, iar variabila referinta stocheaza adresade memorie a obiectului. Astfel, variabila referinta nu este decat un nume pentru aceazona de memorie. Aceasta nsemna ca variabilele primitive si cele referinta vor avea uncomportament diferit. Aceasta sectiune examineaza mai n detaliu aceste diferente si ilus-treaza operatiile care sunt permise pe tipurile referinta.

    3.2.1 Operatorul punct (.)

    Operatorul punct (.) este folosit pentru a selecta o metoda care se aplica unui obiect. Deexemplu, sa presupunem ca avem un obiect de tip Cerc care defineste metoda arie. Dacavariabila unCerc este o referinta catre un Cerc, atunci putem calcula aria (si salva aceastaarie ntr-o variabila de tip double) cercului referit astfel:

    double arieCerc = unCerc.arie() ;

    Este posibil ca variabila unCerc sa retina referinta null. In acest caz, aplicarea operatoruluipunct va genera o exceptie de tipul NullPointerException la executia programului. Deobicei aceasta exceptie va determina terminarea anormala a programului.Operatorul punct poate fi folosit si pentru a accesa componentele individuale ale unuiobiect, daca cel care a proiectat obiectul permite acest lucru. Capitolul urmator descriecum se poate face acest lucru; tot acolo vom explica de ce n general este preferabil ca sanu se permita accesul direct la componentele individuale ale unui obiect.

    3.2.2 Declararea obiectelor

    Am vazut deja care este sintaxa pentru declararea variabilelor primitive. Pentru obiecteexista o diferenta importanta. Atunci cand declaram o referinta, nu facem decat safurnizam un nume care poate fi utilizat pentru a referi un obiect stocat n prealabil nmemorie. Totusi, declaratia n sine nu furnizeaza si acel obiect. Sa presupunem, de exem-plu, ca avem un obiect de tip Cerc caruia dorim sa i calculam aria folosind metoda arie().Sa consideram secventa de instructiuni de mai jos:

    Cerc unCerc ; //unCerc poate referi un obiect de tip Cercdouble arieCerc = unCerc.arie() ; //calcul arie pentru cerc

    Totul pare n regula cu aceste instructiuni, pana cand ne aducem aminte ca unCerc estenumele unui obiect oarecare de tip Cerc, dar nu am creat nici un cerc efectiv. In consecinta,dupa ce se declara variabila unCerc, aceasta va contine valoarea null, ceea ce nseamna ca

  • 28 CAPITOLUL 3. REFERINTE

    unCerc nca nu refera un obiect Cerc valid. Aceasta nseamna ca a doua linie de programeste invalida, deoarece ncercam sa calculam aria unui cerc care nca nu exista. In exemplulde fata chiar compilatorul va detecta eroarea, afirmand ca unCerc nu este initializat.In alte situatii mai complexe compilatorul nu va putea detecta eroarea si se va genera oNullPointerException n timpul executiei programului.Singura posibilitate (normala) de a aloca memorie unui obiect este folosirea cuvantuluicheie new. new este folosit pentru a construi un nou obiect. O posibilitate de a face acestlucru este:

    Cerc unCerc ; //unCerc poate referi un obiect de tip CercunCerc = new Cerc() ; //acum unCerc refera un obiect alocatdouble arieCerc = unCerc.arie() ; //calcul arie pentru cerc

    Remarcati parantezele care se pun dupa numele obiectului.Adeseori programatorii combina declararea si initializarea obiectului ca n exemplul demai jos:

    Cerc unCerc = new Cerc() ; //acum unCerc refera un obiect alocatdouble arieCerc = unCerc.arie() ; //calcul arie pentru cerc

    Multe obiecte pot fi de asemenea construite cu anumite valori initiale. De exemplu, obiec-tul de tip Cerc ar putea fi construit cu trei parametri, doi pentru coordonatele centruluisi unul pentru lungimea razei.

    Cerc unCerc = new Cerc(0,0,10) ; //cerc cu centru in origine si de raza 10double arieCerc = unCerc.arie() ; //calcul arie pentru cerc

    3.2.3 Colectarea de gunoaie (garbage collection)

    Deoarece toate obiectele trebuie construite, ne-am putea astepta ca atunci cand nu maieste nevoie de ele sa trebuiasca sa le distrugem. Totusi, n Java, cand un obiect dinmemorie nu mai este referit de nici o variabila, memoria pe care o consuma va fi eliberataautomat. Aceasta tehnica se numeste colectare de gunoaie.

    3.2.4 Semnificatia lui =

    Sa presupunem ca avem doua variabile de tipuri primitive x si y. Atunci, semnificatiainstructiunii de atribuire

    x = y ;

    este simpla: valoarea stocata n y este stocata n variabila primitiva x. Modificarile ulte-rioare ale lui x sau y nu au efecte asupra celeilalte.Pentru obiecte, semnificatia lui = este aceeasi: se copiaza valorile stocate. Daca x si ysunt referinte (de tipuri compatibile), atunci, dupa operatia de atribuire, x va referi acelasiobiect ca si y. Ceea ce se copiaza n acest caz sunt adrese. Obiectul pe care x l refereanainte nu mai este referit de x. Daca x a fost singura referinta catre acel obiect, atunciobiectul nu mai este referit acum de nici o variabila si este disponibil pentru colectarea degunoaie. Retineti faptul ca obiectele nu se copiaza.

  • 3.2. FUNDAMENTE DESPRE OBIECTE SI REFERINTE 29

    Iata cateva exemple. Sa presupunem ca dorim sa cream doua obiecte de tip Cerc pentrua calcula suma ariilor lor. Cream mai ntai obiectul cerc1, dupa care ncercam sa creamobiectul cerc2 prin modificarea lui cerc1 dupa cum urmeaza (vezi si Figura 3.2):

    Cerc cerc1 = new Cerc(0,0,10) ; //un cerc de raza 10Cerc cerc2 = cerc1 ;cerc2.setRaza(20) ; // modificam raza la 20 ;double arieCercuri = cerc1.arie() + cerc2.arie() ; //calcul arie

    Cerc(0,0,10)

    cerc1HHj

    Cerc(0,0,20)cerc1*

    cerc2HHj Cerc(0,0,10) cerc1

    HHY

    cerc2

    Figura 3.2 cerc1 si cerc2 indica acelasi obiect. Modificarea razei lui cerc2 implica simodificarea razei lui cerc1.

    Acest cod nu va functiona corect, deoarece nu s-a construit decat un singur obiect de tipCerc. Astfel, cea de-a doua instructiune nu face decat sa spuna ca cerc2 este un alt numepentru cerc1, construit anterior. Cercul construit n prima linie are acum doua nume. Atreia instructiune modifica raza cercului la 20, dar de fapt se modifica raza unicului cerccreat, deci ultima linie aduna aria aceluiasi cerc de raza 20.Secventa de cod corecta ar fi:

    Cerc cerc1 = new Cerc(0,0,10) ; //un cerc de raza 10Cerc cerc2 = new Cerc() ;cerc2.setRaza(20) ; // modificam raza la 20 ;double arieCercuri = cerc1.arie() + cerc2.arie() ; //calcul arie

    La o prima vedere, faptul ca obiectele nu pot fi copiate, pare sa fie o limitare severa. Inrealitate nu este deloc asa, desi ne trebuie un pic de timp pentru a ne obisnui cu acestlucru. Exista totusi anumite situatii cand chiar trebuie sa copiem obiecte; n aceste situatiise va folosi metoda clone(). clone() foloseste new pentru a crea un nou obiect duplicat.Totusi, n acesta lucrare metoda clone() nu este folosita.

    3.2.5 Transmiterea de parametri

    Din cauza ca apelul se face prin valoare, parametri actuali (de apel) se transpun nparametri formali folosind atribuirea obisnuita. Daca parametrul trimis este un tip referinta,atunci stim deja ca prin atribuire atat parametrul formal, cat si parametrul de apel vorreferi acelasi obiect. Orice metoda aplicata parametrului formal este astfel implicit aplicatasi parametrului de apel. In alte limbaje de programare acest tip de apel se numeste apelareprin referinta. Utilizarea acestei notiuni n Java ar fi oarecum nepotrivita, deoarece ne-arputea face sa credem ca transmiterea referintelor s-ar face n mod diferit. In realitate,transmiterea parametrilor nu s-a modificat; ceea ce s-a modificat sunt parametrii n sine,care nu mai sunt tipuri primitive, ci tipuri referinta.

  • 30 CAPITOLUL 3. REFERINTE

    3.2.6 Semnificatia lui ==

    Pentru tipurile primitive operatia == are valoarea true daca au valori identice. Pentrutipuri referinta semnificatia lui == este diferita, dar perfect consistenta cu discutia dinparagraful anterior. Doua variabile referinta sunt egale via == daca ele refera acelasiobiect (s-au ambele sunt null). Sa consideram urmatorul exemplu:

    Cerc cerc1 = new Cerc(0,0,10) ; //un cerc de raza 10Cerc cerc2 = new Cerc(0,0,10) ; //un alt cerc tot de raza 10Cerc cerc3 = cerc2 ;

    In acest caz avem doua obiecte. Primul este cunoscut sub numele de cerc1, al doilea estecunoscut sub doua nume: cerc2 si cerc3. Expresia cerc2 == cerc3 este adevarata. Totusi,desi cerc1 si cerc2 par sa refere obiecte care au aceeasi valoare, expresia cerc1 == cerc2este falsa, deoarece ele refera obiecte diferite. Aceleasi reguli se aplica si pentru operatorul!=.Cum facem nsa pentru a vedea daca obiectele referite sunt identice? De exemplu, cumputem sa verificam faptul ca cerc1 si cerc2 refera obiecte Cerc care sunt egale? Obiectelepot fi comparate folosind metoda equals. Vom vedea n curand un exemplu de folosire alui equals, n care vom discuta despre tipul String (paragraful 3.3). Fiecare obiect are ometoda equals, care, n mod implicit, nu face altceva decat testul ==. Pentru ca equals safunctioneze corect, programatorul trebuie sa redefineasca aceasta metoda pentru obiectelepe care le creaza.

    3.2.7 Suprancarcarea operatorilor pentru obiecte

    In afara unei singure exceptii pe care o vom discuta n paragraful urmator, operatorii nupot fi definiti pentru a lucra cu obiecte2. Astfel, nu exista operatorul < pentru nici unfel de obiect. Pentru acest scop, va trebui definita o metoda, cum ar fi lessThan, care varealiza comparatia.

    3.3 Siruri de caractere (stringuri)

    Sirurile de caractere n Java sunt definite folosind obiectul String. Limbajul Java face sapara ca String este un tip primitiv, deoarece pentru el sunt definiti operatorii + si +=pentru concatenare. Totusi, acesta este singurul tip referinta pentru care Java a permissuprancarcarea operatorilor. In rest, String se comporta ca orice alt obiect.

    3.3.1 Fundamentele utilizarii stringurilor

    Exista doua reguli fundamentale referitoare la obiectele de tip String. Prima este aceea ca,exceptand operatorul de concatenare, obiectele de tip String se comporta ca toate celelalteobiecte. A doua regula este aceea ca stringurile sunt ne-modificabile. Aceasta nseamnaca, odata construit, un obiect de tip String nu mai poate fi modificat. Deoarece obiectele

    2Aceasta este o diferenta notabila ntre Java si C++, care permite suprancarcarea operatorilor pentruobiecte. Inginerii de la Sun au considerat ca suprancarcarea operatorilor pentru obiecte aduce mai multeprobleme decat beneficii si au decis ca Java sa nu permita acest lucru

  • 3.3. SIRURI DE CARACTERE (STRINGURI) 31

    de tip String nu se pot modifica, putem folosi linistiti operatorul = pentru ele. Iata unexemplu:

    String vid = "" ;String mesaj = "Salutare!" ;String repetat = mesaj ;

    Dupa aceste declaratii, exista doua obiecte de tip String. Primul este un sir vid, si estereferit de variabila vid. Al doilea este sirul Salutare!, care este referit de variabilele mesajsi repetat. Pentru majoritatea obiectelor, faptul ca obiectul este referit de doua variabilear putea genera probleme. Totusi, deoarece stringurile nu pot fi modificate, partajarea lornu pune nici un fel de probleme. Singura posibilitate de a modifica valoarea catre carerefera variabila repetat este aceea de a construi un nou obiect de tip String si a-l atribuilui repetat. Aceasta operatie nu va avea nici un efect asupra valorii pe care o refera mesaj.

    3.3.2 Concatenarea stringurilor

    Java nu permite suprancarcarea operatorilor pentru tipurile referinta. Totusi, pentrucomoditate, se acorda o exceptie speciala pentru concatenarea de obiecte de tipul String.Atunci cand cel putin unul dintre operanzi este de tip String, operatorul + realizeazaconcatenarea. Rezultatul este o referinta catre un obiect nou construit de tip String. Iatacateva exemple:

    "Sunt" + " curajos!" //rezulta "Sunt curajos!"2 + " mere" //rezulta "2 mere""mere " + 2 //rezulta "mere 2""a" + "b" + "c" //rezulta "abc"

    Sirurile de caractere formate dintr-un singur caracter NU trebuie nlocuite cu constantede tip caracter (constantele caracter sunt de fapt numere).Java dispune si de operatorul += pentru siruri de caractere. Efectul instructiunii str+=expr este str = str + expr. Cu alte cuvinte str va referi un nou String generat de str +expr.Este important sa observam ca ntre atribuirea:

    i=i+5 //i este un intreg

    si atribuirea:

    str=str+"hello" //str este un String

    exista o diferenta esentiala. In primul caz, variabila i este incrementata cu 5; locatia dememorie a lui i nu se modifica. In al doilea caz, se creaza un nou string avand valoareastr+hello. Dupa atribuire, str va referi acest nou string. Fostul string referit va fi supuslui garbage-collection daca nu a existat o alta referinta catre el.

  • 32 CAPITOLUL 3. REFERINTE

    3.3.3 Comparatia stringurilor

    Deoarece operatorul de atribuire functioneaza pe siruri de caractere, am fi tentati sacredem ca functioneaza si operatorii relationali. Acest lucru nu este nsa adevarat.Conform regulii privind suprancarcarea operatorilor, operatorii relationali ( =) nu sunt definiti pentru obiecte de tip String. Mai mult, operatorii == si != ausemnificatia clasica pentru obiecte de tip referinta. De exemplu, pentru doua obiecte detip String, x si y, expresia x == y este adevarata doar daca x si y refera acelasi obiect detip String. Astfel, daca x si y refera obiecte diferite cu continut identic, expresia x == yeste falsa. Acelasi rationament este valabil si pentru !=.Pentru a testa egalitatea a doua obiecte de tip String, se foloseste metoda equals. Expresiax.equals(y) este adevarata daca sirurile de caractere referite de x si de y sunt identice.Un test mai general poate fi realizat cu metoda compareTo. Expresia x.compareTo(y)compara doua obiecte de tip String x si y. Valoarea returnata este un numar negativ, zerosau un numar pozitiv daca x este mai mic, egal, respectiv mai mare decat y.

    3.3.4 Alte metode pentru stringuri

    Lungimea unui obiect de tip String (un sir vid are lungimea 0) poate fi obtinuta cu metodalength(). Deoarece, length() este o metoda parantezele sunt necesare.Exista doua metode pentru a accesa caracterele din interiorul unui String. Metoda charAtreturneaza caracterul aflat la pozitia specificata (primul caracter este pe pozitia 0). Metodasubstring returneaza o referinta catre un String nou construit. Metoda are ca parametripozitia de nceput si pozitia primului caracter neinclus.Iata un exemplu de folosire al acestor metode:

    String mesaj = "Hello" ;int lungimeMesaj = mesaj.length() ; //lungimea este 5char ch = mesaj.charAt(1) ; //ch este eString subSir = mesaj.substring( 2 , 4 ) ; //sub este "ll"

    3.3.5 Conversia de la string la tipurile primitive

    Metoda toString() poate fi utilizata pentru a converti orice tip primitiv la String. Deexemplu, toString(45) returneaza o referinta catre sirul nou construit 45. Majoritateaobiectelor furnizeaza o implementare a metodei toString(). De fapt, atunci cand operatorul+ are un operand de tip String, operandul care nu este de tip String este automat convertitla String folosind metoda toString(). Pentru tipurile de date numerice, exista o variantaa metodei toString() care permite precizarea unei anumite baze. Astfel, instructiunea:

    System.out.println( Integer.toString( 55 , 2 ) ) ;

    are ca efect tiparirea reprezentarii n baza 2 a numarului 55.Pentru a converti un String la un int se poate folosi metoda Integer.parseInt(). Aceastametoda genereaza o exceptie daca String-ul convertit nu contine o valoare ntreaga. Despreexceptii vom vorbi pe scurt n paragraful 3.5. Pentru a obtine un double dintr-un Stringse poate utiliza metoda parseDouble(). Iata doua exemple:

    int x = Integer.parseInt( "75" ) ;double y = Double.parseDouble( "3.14" ) ;

  • 3.4. SIRURI 33

    3.4 Siruri

    Sirurile sunt structura fundamentala prin care se pot retine mai multe elemente de acelasitip. In Java, sirurile nu sunt tipuri primitive; ele se comporta foarte asemanator cu unobiect. Din acest motiv, multe dintre regulile care sunt valabile pentru obiecte se aplicasi la siruri.Fiecare element dintr-un sir poate fi accesat prin mecanismul de indiciere oferit de opera-torul [ ]. Spre deosebire de limbajele C sau C++, Java verifica validitatea indicilor3.In Java, ca si n C, sirurile sunt ntotdeauna indiciate de la 0. Astfel, un sir a cu 3elemente este format din a[0], a[1], a[2]. Numarul de elemente care pot fi stocate n sirul aeste permanent retinut n variabila a.length. Observati ca aici (spre deosebire de String-uri)nu se pun paranteze. O parcurgere tipica pentru un sir ar fi:

    for( int i = 0 ; i < a.length ; i++ )

    3.4.1 Declaratie, Atribuire si Metode

    Un sir de elemente ntregi se declara astfel:

    int[] sir1 ;

    Deoarece un sir este un obiect, declaratia de mai sus nu aloca memorie pentru sir. Variabilasir1 este doar un nume (referinta) pentru un sir de numere ntregi, si n acest momentvaloarea ei este null. Pentru a aloca 100 de numere ntregi, vom folosi instructiunea:

    sir1 = new int[100];

    Acum sir1 este o referinta catre un sir de 100 de numere ntregi.Exista si alte posibilitati de a declara siruri. De exemplu, putem unifica declaratia sialocarea de memorie:

    int[] sir1 = new int[100];

    Se pot folosi si liste de initializare, ca n C sau C++. In exemplul urmator se aloca un sircu patru elemente, care va fi referit de catre variabila sir2:

    int[] sir2 = {3, 4, 6, 19} ;

    Parantezele patrate pot fi puse fie nainte fie dupa numele sirului. Plasarea parantezelornainte de nume face mai vizibil faptul ca este vorba de un sir, de aceea vom folosi aceastanotatie.Declararea unui sir de obiecte (deci nu tipuri primitive) foloseste aceeasi sintaxa. Trebuiesa retineti nsa ca dupa alocarea sirului, fiecare element din sir va avea valoarea null.Pentru fiecare element din sir trebuie alocata memorie separat. De exemplu, un sir cu 5cercuri se construieste astfel:

    3Acesta este un lucru foarte important care vine n ajutorul programatorilor, mai ales a celor ncepatori.Indicii acaror valoare depasesc numarul de elemente alocat sunt adeseori cauza multor erori obscure n Csi C++. In Java, accesarea unui sir cu un indice n afara limitei este imediat semnalata prin exceptiaIndexOutOfBoundsException.

  • 34 CAPITOLUL 3. REFERINTE

    Cerc[] sirDeCercuri ;//declaram un sir de cercurisirDeCercuri = new Cerc[ 5 ] ;

    //alocam memorie pentru 5 referinte la Cercfor( int i = 0 ; i < sirDeCercuri.length ; ++i){

    sirDeCercuri[ i ] = new Cerc() ;//se aloca un obiect Cerc referintei nr. i}

    Programul din Figura 3.4 ilustreaza modul de folosire al sirurilor n Java. In jocul deloterie, sase numere de la 1 la 49 sunt selectate saptamanal. Programul alege aleatornumere pentru 1000 de jocuri. Programul afiseaza apoi de cate ori a aparut fiecare numarn cele 1000 de jocuri. Linia 14 declara un sir de numere ntregi care retine numarul deaparitii ale fiecarui numar. Deoarece indicierea sirurilor ncepe de la 0, adunarea cu 1 esteesentiala. Fara aceasta adunare am fi avut un sir cu elemente de la 0 la 48, si orice accesla elementul cu indicele 49 ar fi generat o exceptie IndexOutOfBoundsException. Cicluldin liniile 15-18 initializeaza valorile sirului cu 0. Restul programului este relativ simplu.Se foloseste din nou metoda Math.random() care genereaza un numar n intervalul [0,1).Rezultatele sunt afisate n liniile 28-31.Dat fiind faptul ca sirul este un tip referinta, operatorul = nu copiaza siruri. De aceeadaca x si y sunt siruri, efectul secventei de instructiuni:

    int[] x = new int[100] ;int[] y = new int[100] ;...x = y ;

    este ca x si y refera acum al doilea sir.Sirurile pot fi utilizate ca parametri pentru metode. Regulile de transmitere se deduc logicdin faptul ca sirul este o referinta. Sa presupunem ca avem o metoda f care accepta unsir de int ca parametru. Apelul si definirea arata astfel:

    f( sirActual ) ; //apelul metodeivoid f( int[] sirFormal) ; //declaratia metodei

    Conform conventiilor de transmitere a parametrilor n Java pentru tipurile referinta, vari-abilele sirActual si sirFormal refera acelasi obiect. Astfel, accesul la sirFormal[i] este defapt un acces la sirActual[i]. Aceasta nseamna ca variabilele continute n sir pot fi mod-ificate de catre metoda. O observatie importanta este aceea ca linia de cod din cadrul luif():

    sirFormal = new int [20] ;

    nu are nici un efect asupra lui sirActual. Acest lucru se datoreaza faptului ca n Javatransmiterea parametrilor se face prin valoare, deci sirFormal este o noua referinta catresir. Instructiunea de mai sus nu face decat sa schimbe sirul catre care refera sirFormal(vezi Figura 3.3).

  • 3.4. SIRURI 35sirActual

    HHjsirActualHHj

    sirFormal

    sirActualHHj

    sirFormalHHj

    a. nainte de apel b. imediat dupa apel c. dupa atribuirea sirFormal=new int[20];

    Figura 3.3 Transmiterea parametrilor n Java

    Deoarece numele sirurilor sunt doar niste referinte, o functie poate sa returneze un sir.

    1. //clasa demonstrativa pentru siruri2. public class Loterie3. {4. //genereaza numere de loterie intre 1 si 495. //afiseaza numarul de aparitii al fiecarui numar6. //declaratii constante:7. public static final int NUMERE = 49 ;8. public static final int NUMERE_PE_JOC = 6 ;9. public static final int JOCURI = 1000 ;10. //main11. public static final void main( String[] args )12. {13. //genereaza numerele14. int [] numere = new int[NUMERE+1] ;15. for( int i=0 ; i < numere.length; ++i )16. {17. numere[i] = 0 ;18. }19.20. for(int i =0 ; i < JOCURI; ++i)21. {22. for( int j = 0 ; j < NUMERE_PE_JOC; ++j )23. {24. numere[ (int)(Math.random()*49)+1 ] ++ ;25. }26. }27. //afisare rezultate28. for( int k = 1 ; k

  • 36 CAPITOLUL 3. REFERINTE

    sa alocam memorie pentru un numar fix de elemente care vor fi stocate. Daca nu stim dela bun nceput cate elemente vor fi stocate n sir, va fi dificil sa alegem o valoare rezonabilapentru dimensiunea sirului. Aceasta sectiune prezinta o metoda prin care putem extindedinamic sirul daca dimensiunea initiala se dovedeste a fi prea mica. Aceasta tehnica poartanumele de expansiune dinamica a sirurilor si permite alocarea de siruri de dimensiunearbitrara pe care le putem redimensiona pe masura ce programul ruleaza.Alocarea obisnuita de memorie pentru siruri se realizeaza astfel:

    int[] a = new int[10] ;

    Sa presupunem ca dupa ce am facut aceasta declaratie, hotaram ca de fapt avem nevoiede 12 elemente si nu de 10. In aceasta situatie putem folosi urmatoarea manevra:

    int original = a ; //salvam referinta lui aa = new int[12] ; //alocam din nou memoriefor(int i=0; i < 10; i++) //copiem elementele in a{

    a[i] = original[i] ;}

    Un moment de gandire este suficient pentru a ne convinge ca aceasta operatie este con-sumatoare de resurse, deoarece trebuie copiat originalul napoi n noul sir a. De exemplu,daca extensia dinamica a numarului de elemente ar trebui facuta ca raspuns la citireade date, ar fi ineficient sa expansionam ori de cate ori citim cateva elemente. Din acestmotiv, de cate ori se realizeaza o extensie dinamica, numarul de elemente este crescut cuun coeficient multiplicativ. Am putea de exemplu dubla numarul de elemente la fiecareexpansiune dinamica. Astfel, dintr-un sir cu N elemente, generam un sir cu 2N elemente,iar costul expansiunii este mpartit ntre cele N elemente care pot fi inserate n sir fara arealiza extensia.Pentru a face ca lucrurile sa fie mai concrete, Figura 3.5 prezinta un program care citesteun numar nelimitat de numere ntregi de la tastatura si le retine ntr-un sir a carui dimen-siune este extinsa dinamic. Functia resize realizeaza expansiunea (sau contractia!) siruluireturnand o referinta catre un sir nou construit. Similar, metoda getInts returneaza oreferinta catre sirul n care sunt citite elementele.La nceputul lui getInts(), nrElemente este initializat cu 0 si ncepem cu un sir cu 5 e-lemente. In linia 36 citim n mod repetat cate un element. Daca sirul este umplut,lucru indicat de intrarea n testul de la linia 36, atunci sirul este expansionat prin apelulmetodei resize. Liniile 51-61 realizeaza expansiunea sirului folosind strategia prezentataanterior. La linia 40, elementul citit este stocat n tablou, iar numarul de elemente cititeeste incrementat. In final, n lina 48 contractam sirul la numarul de elemente citite efectiv.

    1. import java.io.* ;2. //clasa pentru citirea unui numar nelimitat de valori intregi3. public class ReadInts4. {5. public static void main( String[] args )6. {7. int [] array = getInts( ) ;

  • 3.4. SIRURI 37

    8.9. System.out.println("Elementele citite sunt: " ) ;10. for( int i = 0; i < array.length; i++ )11. {12. System.out.println( array[i] ) ;13. }14. }15.16. /* citeste un numar nelimitat de valori intregi17. * fara a trata erorile */18. public static int[] getInts()19. {20. //BufferedReader este prezentata in sectiunile urmatoare21. BufferedReader in = new BufferedReader(22. new InputStreamReader( System.in ) ) ;23.24. int[] elemente = new int[ 5] ; //se aloca 5 elemente25. int nrElemente = 0 ; //numarul de elemente citite26. String s ; //sir in care se citeste cate o linie27.28. System.out.println("Introduceti numere intregi cate unul pe linie:");29.30. try31. {32. //cat timp linia e nevida33. while( (s = in.readLine()) != null )34. {35. int nr = Integer.parseInt( s ) ;36. if( nrElemente == elemente.length ) //sirul a fost "umplut"37. {38. elemente=resize(elemente,elemente.length*2);//dubleaza dimensiunea sirului39. }40. elemente[ nrElemente++ ] = nr ;41. }42. }43. catch( Exception e )44. {45. //nu se trateaza exceptia46. }47. System.out.println( "Citire incheiata." ) ;48. return resize( elemente, nrElemente ) ;//trunchiaza sirul la numarul de elemente citite49. }50.51. public static int[] resize( int[] sir, int dimensiuneNoua )

  • 38 CAPITOLUL 3. REFERINTE

    52. {53. int[] original = sir ;54. int elementeDeCopiat=Math.min(original.length,dimensiuneNoua);55. sir = new int[ dimensiuneNoua ] ;56. for( int i=0; i

  • 3.5. TRATAREA EXCEPTIILOR 39

    9. return ;10. }11. for( int i=0 ; i < args.length; ++i)12. {13. System.out.print( args[i] ) ;14. }15. }16. }

    3.5 Tratarea exceptiilor

    Exceptiile sunt obiecte care retin informatie si care sunt transmise n afara secventelorreturn. Exceptiile sunt propagate napoi prin secventa de functii apelate pana cand o anu-mita metoda prinde exceptia. Exceptiile sunt folosite pentru a semnala situatii exceptie,cum ar fi erorile.De fiecare data cand o exceptie este ntalnita ntr-o metoda a unei clase, programul vapermite recuperarea pierderilor cauzate de exceptie si se va ncheia fara a cauza cadereasistemului. Prin pregatirea tratarii conditiilor de exceptie n care va ajunge executiaprogramului, se va crea un program mult mai prietenos pentru utilizator. Un program Javapoate detecta erori si apoi indica sistemului de executie ce erori a ntalnit prin generareaunor conditii de exceptie ce vor duce la oprirea executiei si afisarea unui cod de eroare,sau daca doriti sa tratati unele exceptii ntr-un mod propriu, puteti folosi o clauza catchpentru a obtine controlul ntr-o situatie de exceptie.

    3.5.1 Procesarea exceptiilor

    Secventa de cod din Figura 3.6 prezinta modul de folosire al exceptiilor. Secventa decod care ar putea genera o exceptie care sa fie propagata este inclusa ntr-un bloc try.Blocul try se extinde de la linia 12 la linia 16. Imediat dupa blocul try trebuie sa aparasecventele de tratare a exceptiilor. Programul sare la secventa de tratare a exceptiilordoar n situatia n care se genereaza o exceptie; n momentul generarii exceptiei, blocultry din care exceptia provine se considera a fi ncheiat.Fiecare dintre blocurile catch este ncercat pe rand pana cand se gaseste o secventa detratare adecvata. Deoarece Exception se potriveste cu toate exceptiile generate, ea esteadecvata pentru orice fel de exceptie generata n blocul try. Exceptiile generate de secventatry din programul nostru pot fi IOException generate de readLine daca apare o eroare lacitire, si NumberFormatException generata de parseInt daca linia citita de la tastatura nupoate fi convertita la int.In cazul unei exceptii se executa codul din blocul catch -n situatia noastra linia 19. Dupaaceasta blocul catch si blocul continand cuplul try/catch se considera ncheiate. Un mesajreferitor la eroarea generata este tiparit folosind obiectul de tip Exception numit e. Putemalege sa facem si alte actiuni n caz de eroare, cum ar fi furnizarea de mesaje de eroaremai detaliate etc.

    1. import java.io.* ;2.

  • 40 CAPITOLUL 3. REFERINTE

    3. public class DivideByTwo4. {5. public static void main( String[] args )6. {7. //BufferedReader este prezentata in sectiunile urmatoare8. BufferedReader in = new BufferedReader(9. new InputStreamReader( System.in ) ) ;10.11. System.out.println("Introduceti o valoare intreaga: ") ;12. try13. {

    //aceasta linie poate genera o exceptie14. int x = Integer.parseInt( in.readLine() ) ;15. System.out.println( "Jumatatea lui "+x+"este"+(x/2)) ;16. }17. catch( Exception e )18. {//aceasta instructiune se executa daca linia 14 a generat o exceptie19. System.out.println( e ) ;20. }21. }22.}

    Figura 3.6 Program simplu pentru ilustrarea exceptiilor

    Se pot preciza diferite tipuri de instructiuni pentru fiecare tip de exceptie ntalnita uti-lizand instructiunea throw. De asemenea, puteti avea propriile obiecte definite ca exceptii,prin care sa tratati anumite evenimente speciale care se pot ntampla pe timpul executieiprogramului. Pentru a va crea o clasa proprie de exceptii, trebuie ca aceasta sa fie osubclasa4 a clasei Exception.

    public class NewException extends Exception{...}

    Acum puteti trata exceptia n modul dorit:

    ...try{...throw new NewException(e);...

    }catch(NewException e)

    4Despre conceptul de mostenire vom discuta n capitolul 5.

  • 3.5. TRATAREA EXCEPTIILOR 41

    {...//tratarea noii exceptii}catch(Exception e){...//tratarea unor erori generale}...

    Dupa cum am mai spus dupa tratarea unei exceptii este ignorata orice secventa deinstructiuni. Totusi, daca este neaparata nevoie sa se execute anumite operatii, veti invocaclauza finally. Blocul finally este executat si n cazul n care nu are loc nici o exceptie nblocul try.

    try{...}finally{...}

    3.5.2 Exceptii uzuale

    Exista mai multe tipuri de exceptii standard n Java. O prima categorie de exceptii o con-stituie exceptiile de executie standard (standard runtime exceptions) cum ar fi mpartireaunui ntreg la 0 sau accesarea unui element de tablou cu indice ilegal. Avand n vederefaptul ca aceste exceptii pot aparea practic n orice secventa de program, ar fi o muncasisifica sa definim secvente de tratare a unor astfel de exceptii. Daca se furnizeaza un bloccatch aceste exceptii se comporta exact la fel ca celelalte exceptii. Daca apare o exceptiestandard pentru care nu exista un bloc catch aceasta se propaga normal, trecand chiar si defunctia main. In aceasta situatie, exceptia produce o terminare anormala a programului,nsotita de un mesaj de eroare. Figura 3.7 prezinta cateva dintre cele mai uzuale eroristandard de executie.

    EXCEPTIE STANDARD DE EXECUTIE SEMNIFICATIE

    ArithmeticException Depasire sau mpartirea unui ntreg la 0

    NumberFormatException Conversie nepermisa a unui String la un tip numeric

    IndexOutOfBoundsException Indice ilegal ntr-un sir sau String

    NegativeArraySizeException Tentativa de a crea un sir cu nr. negativ de elemente

    NullPointerException Tentativa de a folosi o referinta care are valoarea null

    SecurityException Incalcare de securitate n timpul executiei

    Figura 3.7 Cateva exceptii de executie uzuale.

  • 42 CAPITOLUL 3. REFERINTE

    Majoritatea exceptiilor sunt de tipul exceptii standard tratate (standard checked excep-tions). Daca se apeleaza o metoda care poate genera direct sau indirect o astfel deexceptie, atunci programatorul fie trebuie sa o trateze cu un bloc de tip catch sau saindice explicit faptul ca exceptia urmeaza sa fie propagata prin folosirea clauzei throwsn antetul metodei. Retineti faptul ca exceptia tot va trebui tratata la un moment dat,deoarece metoda main (care este la ultimul nivel) nu poate avea o clauza throws.

    EXCEPTIE STANDARD TRATATA SEMNIFICATIE

    java.io.EOFException Terminare de fisier nainte de ncheierea citirii

    java.io.FileNotFoundException Fisierul nu a fost gasit pentru a fi deschis

    java.io.IOException Cuprinde majoritatea erorilor de intrare/iesire

    InterruptedException Aruncata de metoda Thread.Sleep

    Figura 3.8 Exceptii standard tratate uzual

    Ultima categorie de exceptii sunt erorile care nu sunt prinse de Exception. De obicei acesteexceptii nu pot fi tratate. Cea mai uzuala este OutOfMemoryError. Pentru a prinde oriceexceptie posibila, prindeti un obiect de tip Throwable si utilizati clauza throws. Aceastaclau