Sunteți pe pagina 1din 197
Cuprins 1 Introducere in Java 1 1.2 13 14 15 16 Ce este Java ? 1.1.1 Limbajul de programare Java, 1.1.2. Platforme de lueru Java 1.13 Java: un limbaj compilat si interpretat Primal program Structura lexical a limbajului Java 13.1 Setul de caractere 1.3.2 Cuvinte cheie 1.3.3 Identificatori 134° Literali 1.3.5 Separatori 13.6 Operatori 13.7 Comentarii Tipuri de date si variabile 14.1 Tipuri de date 14.2 Variabile Controlul executiei 15.1 Instructiuni de decizie 1.5.2 Instructiuni de salt 1.5.3 Instructiuni pentru tratarea exceptiilor 1.5.4 Alte instruetiuni Vectori 1.6.1 Crearea unui vector 1.6.2 Tablouri multicimensionale 1.63 Dimensiunea unui vector 1.6.4 Copierea vectorilor W i u 12 13 4 16 16 16 7 iv 19 19 20 21 21 22 24 24 25 26 26 26 26 28 28 29 1.6.5 Sortarea vectorilor - clasa Arrays 6... 5 + 1.6.6 Vectori cu dimensiune variabilé si eterogeni Siruri de caractere Folosirea argumentelor de la linia de comandi 1.8.1 Transmiterea argumentelor 1.8.2 Primirea argumentelor 1.8.3 Argumente numerice Obiecte si clase 21 22 23 26 Ciclul de viati al unui obiect 2.1.1 Crearea obiectelor 2.1.2 Folosirea obiectelor 2.1.3 Distrugerea obiectelor Crearea claselor 2.2.1 Declararea claselor 2.2.2 Extinderea claselor 2.2.3 Corpul unei clase 2.24 Constructorii unei clase 2.2.5 Declararea variabilelor 2.2.6 this si super Implementarea metodelor 23.1 Declararea metodelor 2.3.2 Tipul returnat de o metod 2.3.3. Trimiterea parametrilor c&tre o metoda, 2.3.4 Metode cu numar variabil de argumente 2.3.5 Supraincércarea si supradefinirea metodelor Modificatori de acces Membri de instant si membri de clas 2.5.1 Variabile de instant’ si de clas 2.5.2 Metode de instant si de clasit 2.5.3 Utilitatea membrilor de clas 2.54 Blocuri statice de initializare Clase imbricate 2.6.1. Definirea claselor imbricate 2.6.2 Clase interne 2.6.3. Identificare claselor imbricate 2.6.4 Clase anonime Clase si metode abstracte CUPRINS sees 29 30 30 31 31 32 34 35 35 35 37 38 39 39 40 Al 42 46 49 50 50 52 53 56 57 58 5g 5g 61 62 63 6. 64 66 66 67 CUPRINS 2.7.1 Declararea unei clase abstracte 2.7.2 Metode abstracte 28 Clasa Object 2.8.1 Orice clas are o superclass 282 Clasa Object 2.9 Conversii automate intre tipuri 2.10 Tipul de date enumerare 3. Exceptii 3.1 Ce sunt exceptiile ? 3.2. *Prinderea” si tratarea exceptiilor 33. "Arunearea” exceptillor 34 Avantajele tratirii exceptiilor 34.1 Separarea codului pentru tratarea erorilor 3.4.2 Propagarea erorilor 34.3. Gruparea erorilor dupa tipul lor 3.5. Ierarhia claselor ce descriu exceptii 3.6 Exceptii la executie 3.7 Crearea proprillor exceptii 4. Intrari si iesiri 4.1 Introdueere 4.1.1 Ce sunt fluxnrile? 4.1.2 Clasificarea fluxurilor 4.1.3 Ierathia claselor pentru lucrul cu fluxuri 4.14 Metode comune fluxurilor 4.2 Folosirea fluxurilor 4.2.1 Floxuri primitive 4.2.2 Fluxuri de procesare 4.23 Crearea unui flux 4.2.4 Fluxuri pentru luerul cu fisiere 4.2.5 Citirea si scrierea ou buffer 4.2.6 Concatenarea fluxnrilor 4.2.7 Fluxuri pentru filtrarea datelor 428 Clasele DataInputStream si DatautputStream . . . . 4.3. Intrati si iesiri formatate 43.1 Intréri formatate 4.3.2 lesiri formatate 68 68 7 7 7 75 17 77 82 85 85 87 89 90 aL 92 95 95 95 96 98 99 99 100 101 103 105 107 108 109 110 110 i CUPRINS 4.4 Fluxuri standard de intrare si iesire ut 44.1 Afisarea informatiilor pe ecran 2 44.2 Citirea datelor de la tastaturd, 12 44.3 Redirectarea fluxurilor standard 113 444 Analiza lexicala pe fluxuri (clasa StreamTokenizer) . . 115 4.5 Clasa RandomAccesFile (fisiere ou acces direct) uy 4.6 ClasaFile ug Interfete 121 5.1 Introdncere 121 5.11 Ce este o interfata ? 121 5.2 Folosirea interfetelor 122 5.21 Definirea unei interfete 122 5.2.2 Implementarea unei interfete 123 5.2.3 Exemplu: implementarea unei stive 124 5.3. Interfete si clase abstracte 129 5.4 Mostenire multipla prin interfete 130 5.5 Utilitatea interfetelor 132 5.5.1 Crearea grupurilor de constante 132 5.5.2 Transmiterea metodelor ca parametei 133 5.6 InterfajaFilenameFilter ©... 0.0.02... 000005 134 5.6.1 Folosirea claselor anonime 137 5.7 Compararea obiectelor 138 5.7.1 Interfata Comparable 139 5.7.2. Interfata Comparator ML 5.8 Adaptor 142 Organizarea claselor 145 6.1 Pachete M45 6.1.1 Pachetele standard (J2SDK) 45 6.1.2 Folosirea membrilor unui pachet, 146 6.1.3 Importul unei clase sau interfete ur 6.14 Importul In cerere dintr-un pachet, us 6.1.5 Imporbul static 14g 6.1.6 Crearea unui pachet 150 6.1.7 Denumirea unui pachet 151 6.2 Organizarea figierelor 152 6.2.1 Organizarea figierelor sursi 152 CUPRINS 6.2.2 Organizarea unititilor de compilare (class) 6.2.3 Necesitatea organizirii fisierelor 6.24 Setarea c&ii de cautare (CLASSPATH) 63° Arhive JAR 6.3.1 Folosirea utilitarului jar 6.3.2 Executarea aplicatillor arhivate 7 Colectii 7.1 Introducere 2 Interfete ce descriu colectii 3. Implementiti ale colectitlor 4 Folosirea eficienti a colectiilor 5 Algoritmi polimorfici 6 Tipuri generice 7 Iteratori si enumeriri 8 Serializarea obiectelor 8.1 Folosirea serializérii 8.1.1 Serializarea tipurilor primitive 8.1.2. Serializarea obiectelor 8.1.3 Clasa ObjectOutputStream 8.14 Clasa ObjectInputStream 8.2. Obiecte serializabile 8.2.1 Implementarea interfetei Serializable 8.2.2 Controlul serializérii 83. Personelizarea serializérii obiectelor 83.1 Controlul versiunilor claselor 83.2. Securizarea datelor 8.3.3 Implementarea interfetei Externalizable 84 Clonarea obiectelor 9 Interfata graficd cu utilizatorul 9.1 Introducere 9.2 Modelul AWT 9.2.1 Componentele AWT 9.2.2 Suprafete de afigare (Clasa Container) 9.3. Gestionarea pozitionarii 9.3.1 Folosirea gestionarilor de pozitionare 154 155 156 157, 158 159 161 161 162 166 168 170 171 172 177 v7 179 180, 180 181 183 183 184 187, 188 193 194 196 199 199 200 202 204 206 207 94 95 9.6 © 93.2 Gestionarul FlowLayout 9.33. Gestionarul BorderLayout 934 Gestionarul GridLayout 935 Gestionarul CardLayout 9.36 Gestionarul GridBagLayout 93.7 Grupares componentelor (Clasa Panel) Tratarea evenimentelor 94.1 Exemplu de tratare a evenimentelor 94.2 Tipuri de evenimente 9.4.3. Folosirea adaptorilor si a claselor anonime Folosirea ferestrelor 9.5.1 Clasa Window 95.2 Clasa Frame 95.3 Clasa Dialog 95.4 Clasa FileDialog Folosirea meninrilor 9.6.1 Ietarhia claselor ce descriu meniuri 9.6.2 Tratarea evenimentelor generate de meniuti 9.6.3 Meniuri de context (popup) 9.6.4 Acceleratori (Clasa MenuShortcut) Folosirea componentelor AWT 97.1 Clasa Label 9.7.2 Clasa Button. 3. Clasa Checkbox 4 Clasa CheckboxGroup 5 Clasa Choice 6 Clasa List 7 8 9 1 pecs Clasa ScrollBar Clasa ScrollPane Clasa TextField 9. 9. 9. 9.7.10 Clasa TextArea 10 Desenarea 10.1 Conceptul de desenare 10.1.1 Metoda paint 10.1.2. Supratete de desenare - clasa Canvas 10.2 Contextul grafic de desenare 10.2.1 Proprietiitile contextului grafic CUPRINS 209 210 211 212 214 218 219 221 224 227 232 232 233 236 239 242 243 246 247 250 250 251 252 253 255 257 259 261 262 263 265 269 269 270 271 274 275 CUPRINS 103 10.4 105 10.6 10.2.2. Primitive grafice Folosirea fonturilor 10.3.1 Clasa Font 10.3.2 Clasa FontMetrics Folosirea culorilor Folosizea imaginilor 10.5.1 Afigarea imaginilor 10.5.2 Monitorizarea incarcatii imaginilor 10.5.3 Mecanismul de “double-buffering” 10.5.4 Salvarea desenelor in format JPEG 10.5.5 Crearea imaginilor in memorie Tipirirea 11 Swing ud 11.2 113 4 5 11.6 7 118 Introdueere M11 JFC 11.1.2 Swing API 11.1.3 AsemAniti si deosebiri cu AWT Folositea ferestrelor 11.2.1 Ferestre interne Clase JComponent Arhitectura modelnlui Swing Folositea modelelor 11.5.1 Tratarea evenimentelor Folositea componentelor 11.6.1 Componente atomice 11.6.2 Componente pentru editare de text 11.6.3 Componente pentru selectarea unor elemente 11.64 Tabele 11.6.5. Arbori 11.6.6 Containere 11.6.7 Dialoguri Desenarea 11.7.1 Metode specifice 11.7.2 Consideratii generale Look and Feel 8 12 Fire de executie 12.1 Introducere 12.2 Crearea unui fir de exccutie 12.2.1 Extinderea clasei Thread 12.2.2 Implementarea interfotei Runnable 12.3 Ciclul de viat al unui fir de executie 12.3.1. Terminarea unui fir de executie 12.3.2 Fire de executie de tip "daemon” 12.3.3 Stabilirea prioritatilor de executie 12.3.4 Sincronizarea firelor de executie 12.3.5. Scenariul produciitor / consumator 12.3.6 Monitoare 12.3.7 Semafoare 12.38 Probleme legate de sincronizare 12.4 Gruparea firelor de executie 12.5 Comunicarea prin fluxuri de tip "pipe” 12.6 Clasele Timer si TimerTask 13 Programare in retea 13.1 Introdueere 13.2 Luerul cu URL-uri 133 Socket-uri 134 Comunicarea prin conexinni 135 Comunicarea prin datagrame 13.6 Trimiterea de mesaje cétre mai multi clienti 14 Appleturi 14.1 Introducere 14.2 Crearea unui applet simplu 14.3 Ciclul de viati al unui applet 14.4 Interfata grafic cu utilizatorul 14.5 Definirea si folosirea parametrilor 14.6 Tag-ul APPLET 14.7 Folosirea firelor de executie in appleturi 14.8 Alte metode oferite de clasa Applet 14.9 Athivarea appleturilor 14.10Restrictii de securitate 14.1. Appleturi care sunt si aplicatii CUPRINS 343 343, 344 345 347. 352 355 357 358) 362 362 367 369 371 37: 376 378 383 383 385, 387 388) 393, 307 401 401 402 404 406 408 410 412 416 420 421 421 CUPRINS 15 Lucrul cu baze de date 151 15.2 153 154 Introducere 15.1.1 Generalititi despre baze de date 15.1.2 JDBC Conectarea la o baz dle date 15.2.1 Inregistrarea unui driver 15.2.2 Specificarea unei baze de date 15.2.3 Tipuri de drivere 15.2.4 Realizarea mei conexiuni Efectuarea de secvente SQL 15.3.1 Interfata Statement 15.3.2 Interfata PreparedStatement 15.33 Interfata CallableStatement 15.34 Obtinerea si prelucrarea reaultatelor 15.35 Interfata ResultSet 15.3.6. Exempla simplu Lucrul cu meta-date 154.1 Interfata DataboseMetaData 154.2 Interfata ResultSetMetaData 16 Lucrul dinamic cu clase 16.1 16.2 Incirearea claselor in memorie Mecanismul reffectiii 16.2.1 Examinarea claselor si interfetelor 16.2.2 Manipularea obiectelor 16.2.3. Lucrul dinamic cu vectori 423 423 423 424 425 426 427 428 430 431 432 434 437 438 438 440 442 442 443 445 445, 452 453 456 460 CUPRINS Capitolul 1 Introducere in Java 1.1 Ce este Java ? Java este 0 tehnologie inovatoare lansatit de compania Sun Microsystems in 1995, care a avut un impact remarcabil asupra intregii comunitati a dez- voltatorilor de software, impunandu-se prin calititi deosebite cum ar fi sim- plitate, robustete si nu in ultimul rand portabilitate. Denumita initial OAK, tebnologia Java este format dintr-un limbaj de programare de nivel inalt pe baza céruia sunt construite o serie de platforme destinate implementirii de aplicatii pentru toate segmentele industriei software. 1.1.1 Limbajul de programare Java Inainte de a prezenta in detalin aspectele tebnice ale limbajului Java, sit am- intim caracteristicile sale principale, care Lau transformat intr-un interval de timp atat de scurt intr-una din cele mai pupulare optiuni pentru dezvoltarea de aplicatii, indiferent de domeniu sau de complexitatea lor. ¢ Simplitate- elimin suprainctrcaren operatorilor, mostenirea multiplit si toate ”facilititile” ce pot provoca scrierea unui cod confuz. ¢ Usurint& in crearen de aplicatii complexe ce folosese programarea in retea, fire de execute, interfati grafick, baze de date, ete. ¢ Robustete - elimink sursele freevente de erori ce apar in programare prin renuntarea la pointeri, administrarea automat a memoriei si elim- i 12 CAPITOLUL 1, INTRODUCERE IN JAVA inarea pierderilor de memorie printr-o procedurié de colectare a obiectelor care nu mai sunt referite, ce ruleaza in fundal (° garbage collector”) ¢ Complet orientat pe obiecte- elimini complet stilul de programare procedural Securitate - este un limbaj de programare foarte sigur, furnizind mecanisme stricte de securitate a programelor concretizate prin: ver- ificarea dinamics a codului pentru detectarea secventelor periculoase, impunerea unor reguli stricte pentru rularea proceselor la distant, ete Neutralitate arhitecturala- comportamentul unei aplicatii Java nu depinde de arhitectura fizick a masinii pe care ruleaz Portabililtate - Java este un limbaj independent de platforma de In- cru, aceeagi aplicatie ruland fir nici o modificare si fir a necesita re- compilarea ei pe sisteme ce operare diferite cum ar fi Windows, Linux, Mac OS, Solaris, ete. Incru care aduce economii substantiale firmelor dezvoltatoare de aplicatii ¢ Este compilat si interpretat, aceasta find solutia eficient’ pentru obtinerea portabilititii ¢ Performant’- clesi mai lent deoat limbajele de programare care genereazit executabile native pentru o anumita platformi de Iucru, compilatorul Java asiguri o performanti ridicati a codului de octeti, astfel incat viteza de lucru putin mai scizuti nu va fi un impediment in dezvoltarea de aplicatii orieat de complexe, inclusiv grafic 3D, animatie, etc ¢ Este modelat dupa C si C++, trecerea de la C, C++ la Java fiicdndu-se foarte usor. 1.1.2 Platforme de lucru Java Limbajul de programare Java a fost folosit la dezvoltarea unor tehnologii ded- icate rezolvarii unor probleme din cele mai diverse domenii. Aceste tehnologii au fost grupate in aga numitele plaiforme de lucry, ce reprezinta seturi de librétii scrise in limbajul Java, precum si diverse programe utilitare, folosite pentru dezvoltarea de aplicatii sau componente destinate unei anume cate gorii de utilizatori LL CE ESTE JAVA ? 13 ¢ J2SE (Standard Edition) Este platforma standard de lueru ce oferi suport pentru crearea de aplicatii mdependente si appleturi De asemenea, aici este inclusi gi tehnologia Java Web Start ce furnizeaz& © modalitate extrem de facil pentru lansarea si instalarea localé a pro- gramelor scrise in Java direct de pe Web, ofetind cea mai comods solutie pentru distributia si actualizarea aplicatiilor Java, J2MB (Micro Edition) Folosind Java, programarea dispozitivelor mobile este extrem de simpls, platforma de lucrn J2ME oferind suportul necesar scrierii de programe dedicate acestui scop. « J2EE (Enterprise Edition) Aceastit platforms oferé APL-ul necesar dezvoltiirii de aplicatii com- plexe, formate din componente ce trebuie si ruleze in sisteme eterogene, cu informatiile memorate in baze de date distribuite, ete. Tot aici gisim si suportul necesar pentru crearea deaplicatii si servieit Web, bazate pe componente cum ar fi servleturi, pagini JSP, ete. Toate distributiile Java sunt oferite gratuit gi pot fi descireate de pe Internet dle Ia adresa “http:/ /java.sun.com” In continuare, vom folosi termenul J2SDK pentru a ne referi la distributia standard J2SE 1.5 SDK (Tiger). 1.1.3. Java: un limbaj compilat si interpretat In fumctie de modul de executie a aplicatiilor, limbajele de programare se ‘impart in dou’ categorii # Interpretate: instructinnile sunt citite linie on linie de un progeam numit interpretor si traduse in instructiuni masin’. Avantajul aces tei solutii este simplitatea si faptul ci fiind interpretat® direct sursa programului obtinem portabilitatea. Dezavantajul evident este viteza de executie redusi. Probabil cel mai cunoscute limbaj interpretat este limbajul Basie. ¢ Compilate: codul sursi al programelor este transformat de compi- lator intr-un cod ce poate fi executat direct de procesor, numit cod 14 CAPITOLUL 1, INTRODUCERE IN JAVA masini Avantajul este executia extrem de rapids, dezavantajul fiind lipsa portabilitatii, codul compilat intr-un format de nivel scizut nu poate fi rulat deeat pe platforma de Iucru pe care a fost compilat. Limbajul Java combina solutiile amintite mai sus, programele Java fiind atdt interpretate cat si compilate. Asadar vom avea la dispozitie un compi- lator responsabil cu transformarea surselor programului in aga numitul cod de octefi, precum si un interpretor ce va executa respectivul cod de octeti Codul de octeti este diferit de codul magins. Codul masini este reprezen- tat de o succesiune de instructiuni specifice unui anumit procesor si unei an- umite platforme de lucru reprezentate im format binar astiel incat si poata fiexecutate far a mai necesita nici o prelucrare. Codurile de octeti sunt seturi de instructiuni care seamini cu codul seris in limbaj de asamblare si sunt generate de compilator independent de mediul de lucru. In timp ce codul masini este executat direct de citre procesor si poate fi folosit numai pe platforma pe care a fost creat, codul de octeti este interpretat de medin! Java. si de aceea poate fi rulat pe orice platform’ pe care este instalati’ medinl de executie Java Prin magina viriualé Java (JVM) vom intelege mediul de executie al aplicatiilor Java. Pentru ca un cod de octeti si poati fi executat pe un anumit calculator, pe acesta trebuie si fie instalatd o masin& virtual’ Java. Acest Iueru este realizat automat de cétre distributia J2SDK. 1.2. Primul program Crearea oricétei aplicatii Java presupune efectuarea urmstorilor pasi 1. Seriererea codului sursa: class Firstapp { public static void main( String args[]) { System. out.printIn ("Hello world!") ; + 3 1.2. PRIMUL PROGRAM 15 ‘Toate aplicatiile Java contin o clasi principali(primara) in care trebuie si se gaseascit metoda main. Clasele aplicatiei se pot gasi fie intr-un singur fisier, fie m mai multe 2, Salvarea figierelor sursi Se va face in figiere care au obligatoriu extensia java, nici o alta exten- sie nefiind acceptatil, Este recomandat ca figierul care contine codul sursit al clasei primare s& aibé acelagi nume cu cel al clasei, desi acest. lucru nu este obligatoriu. $i presupunem ci am salvat exemplul de mai sus in figierul C:\intro\FirstApp. java. 3. Compilarea aplicatiei Pentru compilare vom folosi compilatorul javae din distributia J2SDK Apelul compilatorului se face pentru fisierul ce contine clasa principalit a aplicatiei sau pentru orice fisier/figiere cu extensia java. Compilatorul crseazi cate un figier separat pentru fieeare clas a programului. Acestea au extensia class gi implicit sunt plasate in acelagi director cu fisierele surs8. javac FirstApp. java In cazul in care compilarea a reusit va fi generat fisierul PirstApp.clase. 4, Rularea aplicatiei Se face cu interpretorul java, apelat pentru unitatea de compilare core- spunzétoare clasei principale. Deoarece interpretorul are ca argument de intrare numele clasei principale si nu numele unui fisier, ne vom pozitiona in directorul ce contine fisierul Firstapp.class si vom apela interpretorul astifel java FirstApp Rularea unei aplicatii care nu foloseste interfat grafic, se va face intr-o fereastra sistem, 16 CAPITOLUL 1, INTRODUCERE IN JAVA ‘Atentie Un apel de genul java c:\intro\Pirstapp.class este gresit! 1.3 Structura lexicala a limbajului Java 1.3.1. Setul de caractere Limbajului Java Iucreaz in mod nativ folosind setul de caractere Unicode. Acesta este un standard international care inlocuieste vechiul set de caractere ASCII si care foloseste pentru reprezentarea caracterelor 2 octeti, ceea ce inseamni ci se pot reprezenta 65536 de semne, spre deosebire de ASCII, unde era posibilé reprezentarea a doar 256 de caractere. Primele 256 caractere Unicode corespund celor ASCII, referirea la celelalte fScdndu-se prin \uxxxx, unde xxxx reprezintt codul caracterului alt caracteristic’ a setului de caractere Unicode este faptul ci intreg, intervalul de reprezentare a simbolurilor este divizat in subintervale mumite blocuri, cateva exemple de blocuri find: Basie Latin, Greek, Arabic, Gothic, Currency, Mathematical, Arrows, Musical, ete. Mai jos sunt oferite cateva exemple de caractere Unicode. # \u0030 - \u0039: cifre ISO-Latin 0-9 # \u0660 - \u0669: cifre arabic-indie 0-9 @ \uO3B1 - \u03C9: simboluri grecesti a — w @ \u2200 - \u22FF : simboluri matematice (¥,3,9, etc.) # \u4e00 - \u9eét: litere din alfabetul Han (Chinez, Japonez, Coreean) Mai multe informatii legate de reprezentarea Unicode pot fi obtinute la adresa, "http://www .unicode.org” 1.3.2 Cuvinte cheie Cuvintele rezervate in Java sunt, ou céteva exceptii, cele din C++ si au fost enumerate in tabelul de mai jos. Acestea nu pot fi folosite ca nume de clase, 1.3, STRUCTURA LEXICALA A LIMBAJULUI JA 7 interfete, varlabile sau metode, true, false, mull nu sunt cuvinte cheie, dar nu pot fi nicl ele folosite ca nume in aplicatii. Cuvintele marcate prin + sunt rezervate, dar mu sunt folosite abstract | double int sbrictip boolean | else interface | super break [extends | long switch byte final native | synchronized case finally [new ‘this catch | float package _| throw char for private | throws class | goto* protected | transient const* | if public | try continue | implements | return void default _| import short volatile do instanceof | static | while Incepand cu versiunea 1.5, mai exist si cuvantul cheie enum, 1.3.3 Identificatori Sunt seovente nelimitate de litere si cifre Unicode, ieepand eu o liter’. Dupi cum am mai spus, identificatorii nu au voie si fie identici cu cuvintele rezer- vate. 1.3.4 Literali Literalii pot fi de urmétoarele tipuri: # Intregi Sunt acceptate 3 baze de numeratie : baza 19, baza 16 (incep cu car acterele Ox) gi baza 8 (incep eu cifra 0) si pot fi de dows tipuri — normali - se reprezinté pe 4 octeti (32 biti) — lungi- se reprezintii pe 8 ovteti (64 biti) gise termini cu caracterul 18 CAPITOLUL 1, INTRODUCERE IN JAVA ¢ Plotanti Pentru ca un literal si fie considerat flotant el trebuie sé aibi cel putin o zecimalé dupii virgulé, si fie in notatie exponential sau si aibi sufixul P sau f pentru valorile normale - reprezentate pe 32 biti, respectiv D sau d pentru valorile duble - reprezentate pe 64 biti Exemple: 1.0,2¢2,3f,4D. # Logici Sunt reprezentati de true - valoarea logic de adevir, respectiv false = valoarea logieé de fale. Atentie Spre deosebire de C++, literalil intregi 1 si 0 mu mai au semnificatia de adevirat, respectiv fals © Caracter Un literal de tip caracter este utilizat: pentru a exprima caracterele co- dului Unicode, Reprezentarea se face fie folosind o liter’, fie o secventt escape scrisi intre apostrofuri. Secventele escape permit specificarea caracterelor care nu au reprezentare graficd si reprezentarea unor car- aotere speciale precum backslash, apostrof, etc. Secventele escape pre- definite in Java sunt —?\b? : Backspace (BS) —?\t?: Tab orizontal (HTT) —?\n? : Linie noua (LF) —\£?: Pagin now (FF) —)\r?: Inceput de rind (CR) —2\"): Ghilimele —\21: Apostrof = \) + Backslash 1.3, STRUCTURA LEXICALA A LIMBAJULUI JA 19 © Siruri de caractere Un literal sir de caractere este format din zero sau mai multe caractere intre ghilimele, Caracterele care formeaz’ sirul pot fi caractere grafice sau secvente escape. Daci sirul este prea lung el poate fi seris ca 0 concatenare de subsiruri de dimensiune mei mic, concatenarea sirurilor realizandu-se cu oper- atorul +, ca inexempluk "ana "+" are "+" mere ". Sirul vid este", Dupi cum vom vedea, orice sir este de fapt o instant a clasei String, definitii in pachetul java. lang. 1.3.5 Separatori Un separator este un caracter care indie sfarsitul unei unitati lexicale si iceputul alteia. In Java separatorii sunt urmatorii: () [];,. Instructiunile unui program se separ’ cu punct si virgula. 1.3.6 Operatori Operatorii Java sunt, cu mici deosebiri, cei din C+ © atribuirea: = © operatori matematici: +, -, *, /, %, +t, -- - Este permis notatia prescurtata de forma Iva op= rval: x += 2 n =3 Existi operatori pentru autoincrementare si autodecrementare (post si pre): x#+, #4, n-=, == Evaluarea expresiilor logice se face prin metoda seurteireuitulué evalu- atea se opreste in momentul in care valoatea de adevar a expresiei este sigur determinata, ‘© operatori logici: &&(and), ||(or), ! (not) operatori relationali: <, <=, >, © operatori pe biti: @(and), |(or), * (xor), ~ (not) © operatoride translatie: <<, >>, >>> (shift la dreapta f&r4 seu) 20 CAPITOLUL 1, INTRODUCERE IN JAVA # operatorul if-else: expresie-logica ? val-true : val-false © operatorul , (virgull) folosit pentru evaluarea seeventialai a operatiilor System.out.printIn(si + "are "+x+" " +52); operatori pentru conversii (cast) : (tip-de-data) int a = (int)’a’; char ¢ = (char)96; inti 100; long 1 = (long)i; //widening conversion (long) 200; (int)12; //narrowing conversion 1.3.7 Comentarii In Java exist trei feluri de comentarii ‘© Comentarii pe mai multe linii, inchise intre /* si */ © Comentarii pe mai multe linii care tin de documentatie, inchise intre /** si */. Textul dintre cele doudl seevente este automat mutat in documentatia aplicatiei de ciitre generatorul automat de documentatie javadoc. © Comentarii pe o singur’ linie, care incep cu //. Observatii ¢ Nu putem serie comentarii in interiorul altor comentarii ‘* Nu putem introduce comentarii in interiorul literalilor caracter sau sit de caractere. ‘* Seoventele /# si */ pot sik apari pe o linie dupa seoventa // dar isi pierd semnificatia, La fel se intampli cu secventa // in comentarii care incep cu /* sau #/. 14, TIPURI DE DATE SI VARIABILE al 1.4 Tipuri de date si variabile 1.4.1 Tipuri de date In Java tipurile de date se impart in dous categorii: tipuri primitive si tipuri referint& Java porneste de la premiza c& orice este un obiect”, prin urmare tipurile de date ar trebui si fie de fapt definite de clase si toate variabilele ar trebui si memoreze instante ale acestor clase (obiecte). In principiu acest lucru este adevirat, insi, pentru usurinta programirii, mai exist si aga numitele tipurile primitive de date, care sunt cele uzuale ¢ aritmetice — intregi: byte (1 octet), short (2), int (4), Long (8) — reale: float (4 octeti), double (8) © caracter: char (2 octet) © logic: boolean (true si false) In alte limbaje de programare formatul si dimensiunea tipurilor primitive de date pot depinde de platforma pe care ruleazt programul. In Java acest lucru nut mai este valabil, orice dependent de o anumita platforms specific fiind eliminatis Vectorii, clasele si interfetele sunt tipuri referinté. Valoarea unei variabile de acest tip este, spre deosebire de tipurile primitive, o referint (adres de memorie) citre valoarea san multimea de valori reprezentaté de variabila respectivi. Exist trei tipuri de date din limbajul C care mu sunt suportate de lim- bajul Java. Acestea sunt: pointer, struct si union Pointerii an fost eliminati din cauzis c& erau o sursi constantit de erori, locul lor fiind Inat de tipul refering, larstruct si union nu isi mai au rostul atat timp céb tipurile compuse de date sunt formate in Java prin intermediul claselor. 22 CAPITOLUL 1, INTRODUCERE IN JAVA 1.4.2. Variabile Variabilele pot fi de tip primitiv sau referinte la obiecte (tip referint). In- diferent de tipul lor, pentru a putea fi folosite variabilele trebuie declarate gi, eventual, initializate. # Declararea variabilelor: Tip nuneVariabila; ¢ Initiolizarea variabilelor: Tip nuneVariabila = valoare; © Declararea constantelor: final Tip numeVariabila; Evident, exist posibilitatea de a declara si initieliza mai multe variabile sau constante de acelagi tip intr-o singur instructiune astiel: ‘Tip variabilat[-valoaret], variabila2[-valoare2],...; Conventia de numire a variabilelor in Java include, printre altele, urmittoarele ctiterii ¢ variabilele finale (constante) se scriu cu majuscule; ¢@ variabilele care nu sunt constante se scriu astfel: prima litera mica iar daci numele variabilei este format din mai multi atomi lexicali, atunci primele litere ale celorlalti atomi se scrin cu majuscule. Exemple final double PI = 3.14; final int MININ-0, MAXIM = 10; int valoare = 100; char cl="j?, c='a’, ¢3=?v’, cd=’a’; long numarElemente = 12345678L; String bauturaMeaPreferata = "apa"; In funetie de locul in care sunt declarate variabilele se impart in urmiitoatele categorii a. Variabile membre, declarate in interiorul unei clase, vizibile pentru toate metodele clasei respective cat si pentru alte clase in functie de nivelul lor de acces (vezi ”Declararea variabilelor membre”). 14, TIPURI DE DATE SI VARIABILE 23 b. Parametri metodelor, vizibili doar in metoda respectivi . Vatiabile locale, declarate intr-o metoda, vizibile doar in metoda re~ spectivil d., Variabile locale, declarate intr-un bloc de cod, vizibile doar in blocul respectiv, e. Parametrii de la tratarea exceptiilor (vezi ” Tratarea exceptiilor”). class Exemplu { //Piecare variabila corespunde situatiei data de numele ei //din enumerarea de mai sus int a; public void metoda(int b) { a=; int ¢ = 10; for(int d=-0; d< 10; d++) { ons + try { a= d/c; } catch(ArithmeticException e) { System.err.printin(e.getMessage()) ; } } + Observatii # Variabilele declarate intr-un for, riman locale corpului ciclului for(int i=0; i 0; im, j--) ¢ oO Atat Io initializare cat si in pasul de iteratie pot fi mai multe instructiuni despirtite prin virgulé. while while (expresie-logica) { } do-while do { wo while (expresie-logica) ; 26 CAPITOLUL 1, INTRODUCERE IN JAVA 1.5.3 Instructiuni pentru tratarea exceptiilor Instructiunile pentru tratarea exceptiilor sunt try-catch-£ inally, respectiv throw si vor fi tratate in capitolul " Exceptii” 1.5.4 Alte instructiuni © break: piriiseste fortat corpul unei structuri repetitive. ¢ continue: termina fortat iteratia curentit a unui ciclu sitrece la urmbtoaren iteratie. e return [valoare]: termina o metoda gi, eventual, returneaza o valo- rare, ‘¢ numeBticketa: : Defineste o etichet’. Desi in Java nn existi goto, se pot defini totusi etichete folosite in expresii de genul: break numeEticheatasau continue numeEticheta, utile pentrn a controla punctul de iesire dintr-o structuri repetitivi, ea inexemplul de mai jos ir0; eticheta: while (i < 10) { System.out.println(* mi); while (j < 10) { ) continue eticheta; ) break eticheta; =i) 1.6 Vectori 1.6.1 Crearea unui vector Crearea unui vector presupune realizarea urmitoarelor etape: 16. VECTORI 7 ¢ Declararea vectorului- Pentru a putes utiliza un vector trebuie, inainte de toate, sil declarim, Acest Iucru se face prin expresii de forma: Tip[] numeVector; sau Tip numeVector[] ; ca in exemplele de mai jos: int[] intregi; String adresel]; * Instantierea Declararea unui vector nu implies si alocarea memoriei necesare pentru retinerea elementelor. Operatiunea de alocare a memoriei, numiti si instantierea vectorului, se realizeazi intotdeauna prin intermediul op- eratorului new. Instantierea unui vector se va face printr-o expresie de genul: numeVector = new Tip[nrElemente] ; unde nrBlemente reprezint. numarul maxim de elemente pe care le poate avea vectorul. In urma instantierii vor fi alocati: nr Elemente * dimensiune(Tip) octeti necesari memoririi elementelor din vector, unde prindémensiune(Tip) am notat numirul de octeti pe care se reprezinti tipul respectiv. v = new int [10]; /faloca spatiu pentru 10 intregi: 40 octeti c = new char[10]; //aloca spatiu pentru 10 caractere: 20 octeti Declararea si instantierea unui vector pot fi fécute simultan astfel: Tip[] numeVector = new Tip[nrElemente] ; 28 CAPITOLUL 1, INTRODUCERE IN JAVA ¢ Initializarea (optional) Dup’ declorarea unui vector, aoesta, poate fi initializat, adica elementele sale pot primi niste valori initiale, evident dacé este cazul pentru asa ceva. In acest caz instantierea nu mai trebuie facut explicit, alocarea memoriei fécdndu-se automat in functie de numa rul de elemente cu care se initializeazi vectorul. String culori{] int []factorial {"Rosu", "Galben", "Verde"}; {1, 1, 2, 6, 24, 120}; Primul indice al unui vector este 0, deci pozitille unui veotor cu n ele- mente vor fi cuprinse intre 0 sin —1. Nu sunt permise constructii de genul Tip numeVector[nrElenente], alocarea memoriei facandu-se doar prin in- termediul opearatorului new. int v{10]; //ilegal int v[] = new int[10]; //corect 1.6.2 Tablouri multidimensionale In Java tablourile multidimensionale sunt de fapt veetori de veetori. De exemplu, crearea si instantierea unei matrici vor fi realizate astfel: Tip matrice[](] = new Tip[nrLinii] [nrColoane] ; natrice[i] este linia é a matricii si reprezint un vector cu nrColoane elemente iar matrice[i] [j] este elemental de pe linia % si coloana 7 1.6.3 Dimensiunea unui vector Cu ajutorul variabilei length se poate afla numirul de elemente al unui vector. int [Ja = new int[S]; // a.length are valoarea 5 int m(](] = new int(5] [10]; // m{0] length are valoarea 10 Pentru a intelege modalitatea de folosire a Ini length trebuie mentionat ca fiecare vector este de fapt o instant’ a unei clase iar length este o variabila publicd a acelei clase, in care este retinut numérul maxim de elemente all vectorului. 16. VECTORI 29 1.6.4 Copierea vectorilor Copierea elementelor unui vector 1 intr-un alt vector b se poate face, fie element cu element, fie cn ajutorul metodei System.arraycopy, ca in exem- plele de mai jos. Dup cum vom vedea, o atribuire de genul b= are altit semnificatie decat copierea elementelor lui 1 in & si mu poate fi folosit in ‘acest scop. int al) int bf) {1, 2, 3, 445 new int [4]; // Varianta 1 for(int i-0; i= 1) prenume = args[1]; else prenume = ""; //valoare implicita System.out.println("Salut "+ nume +" " + prenume) ; Spre deosebire de limbajul C, vectorul primit de metoda main nu contine pe prima pozitie numele aplicatiei, intrucat in Java numele aplicatiei este chiar numele clasei principale, adica a clasei in care se gaseste metoda main. 8 consider in continuare un exemplu simplu in care se doreste afigaren pe ecran a argumentelor primite de la linia de comands: public class Afisare { public static void main (String[] args) { for (int i = 0; i < args.length; i++) System. out. println(args[i]); CAPITOLUL 1, INTRODUCERE IN JAVA Un apel de genul java Afisare Hello Java va produce urmbtorul rezul tat (aplicatia a primit 2 argumente) Hello Java Apelul java Afisare "Hello Java" va produce insi alt rezultat (aplicatia primit un singur argument): Hello Java 18.3 Argumente numerice Argumentele de la linia de comandi sunt primite sub forma unui vector de sivuri (obiecte de tip String). In cazul in care unele dintre acestea reprezintit valori numerice ele vor trebui convertite din siruri in numere, Acest Iucru se realizeaz cu metode de tipul parseTipNumeric aflate in clasa corespun- zatoare tipului in care vrem s& facem conversia: Integer, Float, Double, ete. Si consideriim, de exemplu, c& aplicatia Power ridici un numar real la o putere intreaga, argumentele fiind trimise de la linia de comand sub forma: java Power "1.5" "2" //ridica 1.5 la puterea 2 Conversia celor dowd argumente in numere ge va face astfel public class Power { public static void main(String args[]) { double numar = Double.parseDouble(args[0]); int putere = Integer.parseInt (args[1]) ; System. out.println("Rezultat=" + Nath.pow(numar, putere)); + 3 Metodele de tipul parse TipNumeric pot produce exceptil (erori) de tipul NunberFormatExcept ion in cazul in care sirul primit ca parametru nu reprezint\ un numar de tipul respectiv. Tratarea acestor exceptii este prezentaté in capitolul ” Exoeptii” Capitolul 2 Obiecte si clase 2.1 Ciclul de viata al unui obiect 2.1.1 Crearea obiectelor In Java, ca in otice limbaj de programare orientat-obiect, crearea obiectelor se realizeazi prin instanfierea unei clase si implici, urmaitoarele lucruri # Declararea Presupune specificarea tipului acelui obiect, eu alte cuvinte specificarea clasei acestuia (vom vedea cli tipul unui obiect: poate fi gi o interfat) MNumeClasa numeDbiect; Instantierea Se realizeazii prin intermediul operatorului new gi are ca efect crearea efectiva a obiectului cu alocarea spatiului de memorie corespunzitor. numeObiect = new NumeClasa(); # Initializarea Se realizeaz’ prin intermediul constructorilor clasei respective. Initializarea este de fapt parte integrantii a procesului de instantiere, in sensul ci imediat dup& alocarea memoriei ca efect al operatoruluinew este apelat constructorul specificat. Parantezele rotunde de dup’ numele clase in- dick faptul ci acolo este de fapt un apel la unul din constructorii clasei si nu simpla specificare a numelui clasel Mai general, instantietea gi initializarea apar sub forma: 35 36 CAPITOLUL 2. OBIECTE $I ASE numeObiect = new NumeClasa([argumente constructor]) ; 8 considerim urmitorul exemplu, in care declariim si instantiem dou obiecte din clasa Rectangle, clasi, ce descrie suprafete grafice rectangulare, definite de coordonatele coltului stanga sus (originea) si litimea, respectiv inaltimea. Rectangle ri, 12; ri = new Rectangle() ; 12 = new Rectangle(0, 0, 100, 200); In primal caz Rectangle () este un apel cXtre constructoral claseiRectangle care este responsabil cu initializarea obiectului cu valorile implicite. Dup& cum observim in al doilea caz, initializarea se poate face si cu anumiti para- metri, cu conditia si existe un constructor al clasei respective care si accepte parametrii respectivi Fiecare clasé are un set de constructori care se ocup’ cu initializare obiectelor nou create. De exemplu, clasa Rectangle are urmatorii construc- tori public Rectangle () public Rectangle(int latime, int inaltime) public Rectangle(int x, int y, int latime, int inaltime) public Rectangle (Point origine) public Rectangle (Point origine, int latime, int inaltime) public Rectangle(Point origine, Dimension dimensiune) Declararea, instantieres gi initializarea obiectului pot apirea pe aceeasi linie (cazul cel mai uzwel) Rectangle patrat - new Rectangle(0, 0, 100, 100); Obiecte anonime Este posibili si crearea unor obiecte anonime care servese doar pentru initializarea altor obiecte, caz in care etapa de declarare a referintei obiectului nu mai este prezenti: Rectangle patrat = new Rectangle (new Point (0,0), new Dimension(100, 100)); 2.1, CICLUL DE VIATA AL UNUI OBIECT 37 Spatiul de memorie nu este pre-alocat Declararea unui obiect nu implici sub nici o form’ alocarea de spatiu de memorie pentru acel obiect. Alocarea memoriei se face doar la apelul operatorului new. Rectangle patrat; patrat.x = 10; //Eroare - lipseste instantierea 2.1.2 Folosirea obiectelor dati un obiect reat, el poate fi folosit in urmitoarele sensuri: aflarea unor informatii despre obiect, schimbarea strii sale sau exeoutarea unor actiuni Aceste lucruri se realizeaza prin aflarea sau schimbarea valorilor variabilelor sale, respectiv prin apelarea. metodelor sale. Referirea valorii unei variabile se face prin obiect.variabila De exem- plu clasaRectangle are variabilele publicex, y, width, height, origin. Aflarea valorilor acestor variabile sau schimbarea lor se face prin constructii de genul: Rectangle patrat = new Rectangle(0, 0, 100, 200); System.out.printIn(patrat.width); //afiseaza 100 patrat.x = 10; patrat.y = 20; /fschimba originea patrat.origin = new Point(10, 20); //schimba originea Accesul la variabilele unui obiect se face in conformitate cu drepturile de ‘acces pe care le oferii variabilele respective celorlalte clase. (vezi ” Modifica- tori de acces pentrn membrii unei clase”) Apelul unei metode se face prin obiect.metoda ([parametri]). Rectangle patrat = new Rectangle(0, 0, 100, 200); patrat.setLocation(10, 20); //schimba originea patrat.setSize(200, 300); //schimba dimensiunea Se observ cX valorile variabilelor pot fi modificate indirect prin inter- mediul metodelor sale. Programarea orientats obiect descurajeazi folosiren direct: a variabilelor unui obiect deoarece acesta poate fi adus in stiri in- consistente {ireale). In schimb, pentru fiecare variabilii care descrie starea 38 CAPITOLUL 2. OBIECTE $I ASE obiectului trebuie si existe metode care st permits schimbarea/afiarea val- ctilor variabilelor sale. Acestea se numese metode de accesare, sali metode setter - gettersi au numele de forma set Variabila, respectiv get Variabila. patrat.width = -100; //stare inconsistenta patrat.setSize(-100, -200); //metoda setter //metoda setSize poate sa testeze daca noile valori sunt //corecte si sa valideze sau nu schimbarea lor 2.1.3. Distrugerea obiectelor Malte limbaje de programare impun ca programatorul si tind evidenta obiectelor create si si le distrugi in mod explicit atunci cand nu mai este nevoie de ele, cu alte cuvinte s& administreze singur memoria ocupati de obiectele sale Practica a demonstrat cit aceastit tehnici este una din principalele furnizoare de erori ce duc Ia functionarea defectiuoasi a programelor, In Java programatorul nu mai ate responsabilitatea distrugerii obiectelor sale intracét, in momentul rulérii unui program, simulten cu interpretorul Java, ruleaza si un proces care se ocup’ cu distrugerea obiectelor care nu mai sunt folosite. Acest proces pus la dispozitie de platforma Java de lucru se numeste garbage collector (colector de gunoi), prescurtat ge. Un obiect este eliminat din memorie de procesul de colectare atunci cénd nu mai exist nici o referintit la acesta, Referintele (care sunt de fapt vari- abile) sunt distruse dou moduri: ¢ natural, atunci cand variabila respectivit iese din domeniul situ de viz- ibilitate, de exemplu la terminarea metodei in care ea a fost declarati; © caplicit, daci atribuim variabilei respective valoare null. Cum functioneaz& colectorul de gunoaie ? Colectorul de gunoaie este un proces de prioritate scazuti care se exe ccutit periodic, scaneazi dinamic memoria ocupat de programul Java afiat in execute si marcheazii acele obiecte care au referinte directe sau indirecte. Dupi ce toate obiectele au fost parcurse, cele care au rimas nemarcate sunt eliminate automat din memorie. 2.2, CREAREA CLASELOR 39 Apelul metodei ge din clasa System sugereazi maginii virtuale Java sii *depund eforturi” in recuperarea memoriei ocupate de obiecte care nu mai sunt folosite, fir’ a forta ins pornirea procesului Finalizare Inainte ca un obiect si fie eliminat din memorie, procesul ge da acelui obiect posibilitatea "ss curete dupa el”, apeland metoda de finalizare a obiec- tului respectiv. Uzual, in timpul finalizirii un obiect isi inchide fisierele si socket-urile folosite, distruge referintele cétre alte obiecte (pentru a ussura sarcina colectorului de gunoaie), etc Codul pentru finalizarea unui obiect trebuie seris intt-o metodat specialit numita finalize a clasei ce descrie obiectul respectiv. (vezi ” Clasa Object”) ‘Atentie Nu confundati metoda finalize din Java cu destructorii din C++. Metoda finalize nu are rolul de a distruge obiectul oi este apelat automat inainte de climinarea obiectului respectiv din memorie, 2.2 Crearea claselor 2.2.1 Declararea claselor Clasele reprezintii o modalitate de a introduce noi tipuri de date intr-o aplicatie Java, cealalti modalitate fiind prin intermedial interfetelor. Declararea unei clase respectit urmitorul format general! [public] [abstract] [final] class NumeClasa [extends NumeSuperclasa] (implements Interfatal [, Interfata2 ... ]] t // Corpal clasei + Agadar, prima parte a declaratiei o ocup’ modificatorii clasei. Acestia sunt: 40 CAPITOLUL 2, OBIBCTE $I CLASE © public Implicit, o clas poate fi folositii doar de clasele alate in acelasi pa- chet(librarie) cu clasa respectiva (daca nu se specifick un anume pa- chet, toate clasele din directorul curent sunt considerate a fi in acelasi pochet). O clasi declarati cu public poate fi folositit din orice alti clasi, indiferent de pachetul in care se giseste. abstract, Declaré o clas abstract (gablon). © clasé abstract nu poate fi instantiati, fiind folositi doar pentru a crea un model comun pentru o serie de subclase. (vezi "Clase si metode abstracte”) © final Declari ci respectiva clas nu poate avea subclase, Declarare claselor finale are dou’ seopuri — securitate. unele metode pot astepta ca parametru un obiect al unei anumite clase si nu al unei subclase, dar tipul exact al unui obiect nu poate fi aflat cu exactitate decat in momentul executiei; in felul acesta nu s-ar mai putea realiza obiectivul limbajului Java ca un program care a trecut compilarea si nu mai fie susceptibil de nici 0 eroare. — programare in sprivit orientat-obiect O clasa “perfect” nu tre- buie 58 mai aiba subclase. Dupii numele clasei putem specifica, daci este cazul, faptul cl respectiva clasi este subelasi a unei alte clase cu numele NumeSuperclasa sau/si ci implementeazi una sau mai multe interfete, ale cror nume trebuie separate prin virguli 2.2.2 Extinderea claselor Spre deosebire de alte limbaje de programare orientate-obiect, Java permite doar mogtenirea simpla, ceea ce ineamni ci o clasi poate avea un singur parinte (superclasi). Evident, o clasi poate avea oricéti mogtenitori (sub- clase), de unde rezulti c& multimea tuturor claselor definite in Java poate fi vazuté ca un arbore, ridicina acestuia fiind clasa Object. Asadar, Object este singura clas care nu are pirinte, fiind foarte important in modul de lucru cu obiecte si structuri de date in Java. 2.2, CREAREA CLASELOR AL Extinderea unei clase se realizeaza folosind cuvantul cheie extends: class B extends A {...} // A este superclasa clasei B // B este o subclasa a clasei A subclasii mosteneste de la parintele sit toate variabilele gi metodele care nu sunt private, 2.2.3 Corpul unei clase Corpul unei clase urmeaz’ imediat dupa declararea clasei si este cuprins intre acolade. Continutul acestuia este format din: ¢ Declararea si, eventual, initializarea variabilelor de instant si de clasit (cumosoute impreuni ca variabile membre). © Declararen si implementarea constructorilor ¢ Declararea gi implementarea metodelor de instanta gi de clas (cunos- cute impreunis ca metode membre) * Declararea unor clase imbricate (interne) Spre deosebire de C++, nu este permisti doar declararea metodel in corpul clasei, urmand ca implementare sé fie facut in afara ci, Implementarea metodelor unei clase trebuie si se faci obligatoriu in corpul clasei 1] C+ class A { void metodat() ; int metoda2() { // Tnplementare } } Arimetodai() { /{ Implementare + 42 CAPITOLUL 2. OBIECTE $I I) Java class A { void metodat(){ // Inplenentare } void metoda2(){ // Ynplenentare } } Variabilele unei clase pot avea acelasi nume cu metodele clasei, care poate fi chior numele clase, fir a existe, posibilitatea aparitiel vreunei ambiguitati din punctul de vedere al compilatorului. Acest lucru este inst total nere- comandat dack ne gindim din perspectiva lizibilitstii (claritstii) codului, dovedind un stil ineficient de progamare class A { int A; void A() {}; // Corect pentru compilator // Nerecomandat ca stil de programare 3 ‘Atentie Variabilele si metodele nu pot avea ca nume un cuvént cheie Java 2.2.4 Constructorii unei clase Constructorii unei clase sunt metode speciale care au acelasi nume cu cel al clasei, nu returneazi nici o valoare si sunt folositi pentru initializarea obiectelor acelei clase in momentul instantieri lor. class NumeClasa { (nodificatori] MumeClasa([argumente]) { // Constructor 2.2, CREAREA CLASELOR 43, + + clasé poate avea unul sau mai multi constructori care trebuie ins si difere prin lista de argumente primite. In felul acesta sunt permise diverse tipuri de initializéti ale obiectelor la crearea lor, in functie de numéul para- metrilor cu care este apelat constructorul. Sé consider’im ca exemplu declararea unei clase care descrie notiunea de dreptunghi si trei posibili constructori pentru aceasta clasi. class Dreptunghi { double x, y, w, hy Dreptunghi (double x1, double y1, double wi, double hi) { // Cel mai general constructor xext; yey; wewl; hebl; System.out.printIn("Instantiere dreptunghi"); + Dreptunghi (double wi, double hi) { // Constructor cu doua argumente x=0; y=0; wewl; heb1; System.out .println("Instantiere dreptunghi") ; } Dreptunghi() { // Constructor fara argumente x=0; y=0; w=0; he System.out.printIn("Instantiere dreptunghi"); } } Constructorii sunt apelati automat la instantierea unui obiect. In cazul in care dorim si apelim explicit constructorul unei clase folosim expresia this( argumente ), care apeleazii constructorul corespunziitor (ca argumente) al clasei respec- tive. Aceastii metodé este folositi atunci cand sunt implementati mai multi constructori pentru o clasd, pentru a nu repeta seeventele de cod scrise deja ln constructorii cu mai multe argumente (mai generali). Mai eficient, fara 44 CAPITOLUL 2. OBIECTE $I CLASE a repeta aceleasi seovente de cod in toti constructorii (cum ar fi afigarea mesajului "Instantiere dreptunghi”), clasa de mai sus poate fi rescrisi astfel: class Dreptunghi { double x, 7, ¥, hy Dreptunghi (double x1, double y1, double wi, double hi) { // Inplenentan doar constructorul cel mai general xext; ysyl; wewl; heh; System. out.printIn("Instantiere dreptunghi"); + Dreptunghi (double wi, double hi) { this(0, 0, wi, hi); // Apelam constructorul cu 4 argumente + Dreptunghi() { this(0, 0); // bpelam constructorul cu 2 argumente + 3 Dintr-o subclasit putem apela explicit constructoril superclasel cu expresia super( argumente ) $i presupunem ci dorim si creim clasaPatrat, derivati din clasa Dreptunghi: class Patrat extends Dreptunghi { Patrat(double x, double y, double 4) { super(x, y, 4, d); // kpelam constructorul superclasei + 3 ‘Atentie Apelal expleit al unui constructor nu poate apirea decat intr-un alt con structor si trebuie si fie prima instructiune din constructorul respectiv. 2.2, CREAREA CLASELOR 45, Constructorul implicit Constructorii sunt apelati automat Ja instantierea unui obiect. In cazul in care scriem o clas care nu are declarat nici un constructor, sistemul ti creeazit automat un constructor implicit, care nu primeste nici un argument si care nu face nimic. Deci prezenta constructorilor in corpul unei clase nu este obligatorie. Dac ins scriem un constructor pentru o clasii, care are mai malt de un argument, atunci constructorul implicit (far nici un argument) nu va mai fi furnizat implicit de catre sistem. $& considerim, ca exemplu, urmatoarele declaratii de clase class Dreptunghi { double x, 7, ¥, hj // Nici un constructor 3 class Cerc { double x, y, r} // Constructor cu 3 argumente Cere(double x, double y, double r) { ... 3; } ‘Sa considera acum doui instantieri ale claselor de mai sus: Dreptunghi d = new Dreptunghi(); // Corect: (a fost generat constructorul implicit) Gere c; © = new Cerc(); // Eroare la compilare ! c = new Cerc(0, 0, 100); // Navianta corecta In cazul mosteninii unei clase, instantierea unui obiect din clasa extinsi implica instantierea unui obiect din clasa pirinte. Din acest motiv, fiecare constructor al clasei fiu va trebui sit aibii un constructor cu aceeasi signaturi in pirinte san si apeleze explicit un constructor al clasei extinse folosind expresia super ([arguente]), in caz contrar fiind semnalati o eroare la compilare. 46 CAPITOLUL 2. OBIECTE $I CLASE class A { int x1; ACint x) { this.x = x;} 3 class B extends A { // Corect B() {super (2) ;} Bint x) {super.x = x;} 3 class C extends A { // Eroare 1a compilare ! CQ {super.x = 2;} (int x) {super.x = x;} 3 Constructorii unei clase pot avea urmitorii modificatori de acces public, protected, private si cel implicit. © public In orice alt clas se pot crea instante ale clasei respective, © protected Doar in subclase pot fi create obiecte de tipul clasei respective private In nici o alti clas nu se pot instantia obiecte ale acestei clase. O ast- fel de clas poate contine metode publice (numite "factory methods”) care si fie responsabile cu createa obiectelor, controland in felul acesta diverse aspecte legate de instantierea clasei respective. © impli Doar in clasele din acelagi pachet se pot crea instante ale clasel respec- tive. 2.2.5 Declararea variabilelor Variabilele membre ale unei clase se declara de obicei inaintea metodelor, desi acest Incr nu este impus de cétre compilator. 2.2, CREAREA CLASELOR 47 class NumeClasa { // Declararea variabilelor // Declararea metodelor + Variabilele membre ale unel clase se declark in corpul clasei si nu in corpul unei metode, fiind vizibile in toate metodele respectivei clase. Variabilele declarate in cadrul unci metode sunt locale metodei respective. Declararea unei variabile presupune specificarea urmatoarelor Iucruri: # numele variabilei @ tipul de date al acesteia # nivelul de acces Ia acea variabila din alte clase @ daca este constanté sau nu © daci este variabill, de instant sau de clasi © alti modificatori Generic, o variabilli se declara asttfel (modificatori] Tip numeVariabila [ = valoarelnitiala ]; unde un modificator poate fi * un modificator de acees : public, protected, private (vezi "Mod- ificatori de acces pentru membrii unei clase”) ¢ unul din cuvintele rezervate: static, final, transient, volatile Exemple de declaratii de variabile membre: class Exemplu { double x; protected static int n; public String s = "abcd"; private Point p = new Point(10, 10); final static long MAX = 100000L; 48 CAPITOLUL 2. OBIECTE $I ASE $i analizim modificatorii care pot fi specificati pentru o variabilé, alti decat cei de acces care sunt tratati intr-o sectiune separata: "Specificatori de acees pentru membrii unei clase” static Prezenta lui declari cli o variabili este variabila de clast si nu de Instanta, (vezi ”Membri de instanta gi membri de clasi”) int variabilalnstanta ; static int variabilaClasa; * final Indic& faptul c& valoarea variabilei nu mai poate fi schimbata, cu alte cuvinte este folosit: pentru declararea constantelor. final double PI = 3.14 ; I = 3.141; // Eroare la compilare ! Prin conventie, numele variabilelor finale se seriu cu litere mati. Folosirea lui final aduce o flexibilitate sporita in lucral cu constante, in sensul cA valoarea unei variabile nu trebuie specificatit neapirat Ia declararea ei (ca in exemplul de mai sus), ci poate fi specificatit si ulterior intr-un constructor, dup care ea nu va mai putea fi modificati. class Test { final int MAX; Test) { MAX = 100; // Corect MAX = 200; // Eroare la compilare ! + + ¢@ transient. Este folosit la serializarea obiectelor, pentru a specifica ce variabile membre ale unui obiect nu participa la serializare. (vezi "Serializarea obiectelor”) 2.2, CREAREA CLASELOR 49 # volatile Este folosit pentru a semnala compilatorului sk nu execute anumite optimiziri asupra membrilor unei clase, Este o facilitate avansaté a limbojului Java, 2.2.6 this si super Sunt variabile predefinite care fac referinta, im cadrul unui obieet, la obiectul propriu-zis (this), respectiv la instanta piintelui (guper). Sunt folosite {in general pentru a rezolva conflicte de nume prin referirea explicit a unei variabile sau metode membre. Dupi cum am vitzut, utilizate sub formi de metode au rolul de a apela constructorii corespunzitori ca angumente ai clasei curente, respectiv ai superclasei class A { int x; AO { this (0); 3 AGint x) { this.x x; + void metoda() { x +; } } class B extends A { BO { ‘this (0); } BCint x) { super (x) ; System. out.print1n(x) ; 3 void metoda() { super .metoda() ; 50 CAPITOLUL 2. OBIECTE $I CLASE System. out .printIn (x) ; + 3 2.3 Implementarea metodelor 2.3.1. Declararea metodelor Metodele sunt responsabile cu descrierea comportamentului unui obiect. In- trucét Java este un limbaj de programare complet orientat-obiect, metodele se pot gisi doar in cadrul claselor. Generic, o metoda se declarit astfel: (modificatori] TipReturnat numeMetoda ( [argumente] ) (throws TipExceptiel, TipExceptie2, ...] t // Corpul metodei } unde un modificator poate fi ‘© un specificator de acces : public, protected, private (vezi "Spec- ificatori de acces pentru membrii unei clase”) ‘* unul din cuvintele rezervate: static, abstract, final, native, synchronized $i analizim modificatorii care pot fi specificati pentru o metods, alti decat cei de acces care sunt tratati intr-o sectiune separata. @ static Prezenta Ini declarii ci 0 metodii este de clasii si nu de instant. (vezi ” Membri de instanta si membri de clas”) void metodalnstanta() ; static void metodaClasa(); @ abstract Permite declararea metodelor abstracte. O metodii abstractit este o metod care nu are implementare si trebuie obligatoriu sé faci parte dintr-o clasa abstracta. (vezi "Clase gi metode abstracte”) 23, IMPLEMENTAREA METODELOR, 51 ¢ final Specific’ faptul ci acca metoda nu mai poate fi supradefinitt in sub- clasele clasei in care ea este defini ca fiind final. Acest cru este util daca respectiva metoda are o implementare care nu trebuie schim- batit sub nici o forma in subclasele ei, fiind critic’ pentru consistenta strii unui obiect. De exemplu, stucentilor unei universitasti trebuie si li se calculeze media finala, in fumetie de notele obtinute la examene, im aceeasi manier’, indiferent de facultatea la care sunt. class Student { final float calcMedie(float note[], float ponderi[]) { 3 } class StudentInformatica extends Student { float calcMedie(float note[], float ponderil]) { return 10.00; 3 3// Broare 1a compilare ! @ native In cazul in care avem o libritie important de functi scrise in alt limbaj de programare, cum ar fi C, C++ gi limbajul de asamblare, acestea pot fi refolosite din programele Java, Tebnologia care permite acest lucruse numeste JNI (Java Native Fnterface)si permite asocierea dintre metode Java declarate cu native gi metode native scrise in limbajele de programare mentionate. synchronized Este folosit in cazul in care se lucreag#i cu mai multe fire de executie iar metoda respectiva gestioneazi resurse comune, Are ca efect construirea unui monitor care nu permite executarea metodei, la un moment dat, decat unui singur fir de executie. (vezi "Fire de executie”) 52 CAPITOLUL 2. OBIECTE $I 2.3.2 Tipul returnat de o metoda Metodele pot sat mu si returneze o valoare la terminarea lor. Tipul returnat: poate fi atat un tip primitiv de date sau o referint la un obiect al unei clase. In cazul in care 0 metod’ nu returneazi nimic atunci trebuie obligatorin specificat cuvantul cheie void ca tip returnat: public void afisareRezultat() { System. out .printin("rezultat") ; + private void deseneaza(Shape s) { return; + Daca o metoda trebuie sé returneze o valoare acest Iucru se realizeaza prin intermediul instructiunii return, care trebuie si apara in toate situatiile de terminare a functiei double radical (double x) { if (x >= 0) return Math.eqrt (x) ; else { System.out.printin("Argument negativ | // Eroare 1a compilare // Lipseste return pe aceasta ramura + + In cazul in care in declaratia functiei tipul returnat este un tip primitiv de date, valoarea returnat la terminarea functiei trebuie si aibis obligatorin acel tip sau un subtip al stu, altfel va fi furnizatii oeroare la. compilare. In general, orice atribuire care implicd pierderi de date este tratat de compilator ca eroare int metoda() { return 1.2; // Eroare + int metoda() { 23, IMPLEMENTAREA METODELOR, 53 return (int)1.2; // Corect + double metoda() { return (float)1; // Corect + Dacit valoarea returnati este o referinté la un obiect al unei clase, atunci clasa obiectului returnat trebuie sX coincid sau si fie o subclass a clasei specificate la declararea metodel. De exemplu, fie clasa Poligon si subclasa acesteia Patrat. Poligon metodal( ) { Poligon p = new Poligon(); Patrat t = new Patrat(); if (..) return p; // Corect else return t; // Corect + Patrat metoda2( ) { Poligon p = new Poligon(); Patrat t = new Patrat(); if (..) return p; // Eroare else return t; // Corect 2.3.3 Trimiterea parametrilor catre o metoda Signatura unei metode este dat de numarul si tipul argumentelor primite de acea metodi, Tipul de date al unui argument poate fi orice tip valid al limbajului Java, atat tip primitiv cét si tip referinta. TipReturnat metoda([Tipi argi, Tip2 arg2, ...]) Exemplu 54 CAPITOLUL 2. OBIBCTE $I CLASE void adaugarePersoana(String nume, int varsta, float salariu) // String este tip referinta // int si float sunt tipuri primitive Spre deosebire de alte limbaje, in Java nu pot fi trimise ca parametti ail unei metode referinte la alte metode (functil), ins pot fi trimise referinte la obiecte care si conting implementarea acelor metode, pentru a fi apelate. Pana la aporitia versiunii 1.5, in Java o metoda nu putea primi un numar variabil de argumente, ceea ce inseamna ck apelul imei metode trebuia s& se faci cu specificarea exact a numarului si tipurilor argumentelor. Vom anal- iza intr-o sectiune separati, modalitate de specificare a unui numér variabil de argumente pentru o metodi. Numele argumentelor primite trebuie st difere intre ele si nu trebuie si co- incidé cu numele nici uneia din variabilele locale ale metodei. Pot insi si coincidi cu numele variabilelor membre ale clasei, caz in care diferentierea dintre ele se va face prin intermediul variabile this. class Cerc { int x, y, raza; public Cerc(int x, int y, int raza) { this.x = x; this.y = y; this.raza = raza; + 3 In Java argumentele sunt trimise doar prin valoare (pass-by-value) Acest lucru inseamna ci metoda receptioneaza doar valorile variabilelor prim- ite ca parametri Cand argumentul are tip primitiv de date, metoda nui poate schimba val- area decat local (in cadrul metodei); la revenites din metods variabila are aceeasi valoare ca inaintea apelului, modificirile f’eute im cadrul metodel fi- ind pierdute. Cand argumentul este de tip referinti, metoda mu poate schimba valoarea referintel obiectului, insi poate apela metodele acelui obiect si poate modifica orice variabilé membra accesibilf Agadar, daca dorim cao metoda sii schimbe starea (valoarea) unui argu- ment primit, atunci el trebuie si fie neaparat de tip referinta. 23, IMPLEMENTAREA METODELOR, 55 De exemplu, si considerim clasa Cerc descrisé anterior in care dorim si implementiim o metoda cate s4 returneze parametrii cercului // Varianta incorecta: class Cerc { private int x, y, raza; public void aflaParametri(int valx, int valy, int valr) { // Metoda nu are efectul dorit! valx = x} valy = y; valr = raza; } } Aceastii metod nu va realiza Iucrul propus intrucat ea primeste doar valorile variabilelor valx, valy gi valr si nu referinte la ele (adresele lor de memorie), astfel incat si le poat modifica valorile. In concluzie, metoda nu realizeaz’ nimic pentru c& nu poate schimba valorile variabilelor primite ca argumente. Pentru a rezolva Incrul propus trebuie sé definim o clas suplimentarii care si descrie parametrii pe care dorim sii aft: // Varianta corecta class Param { public int x, y, raza; + class Cerc { private int x, y, raza; public void aflaParametri(Param param) { param.x = x; param.y param.raza + + Argumentul param ore tip referint si, desi nu ii schimbim valoarea (val- aren sa este adresa de memorie la care se gasegte gi nu poate fi schimbati), 56 CAPITOLUL 2. OBIECTE $I CLASE putem schimba starea obiectului, adic informatia propriu-zisi continutié de acesta. Varianta de mai sus a fost dat pentru a clarifica modul de trimitere a argumentelor unei metode. Pentru a afia inst valorile variabilelor care descriu starea unui obiect se folosesc metode de tip getter insotite de metode setter care si permits schimberea stiri obiectului class Cerc { private int x, y, raza; public int getX() { return x; + public void setX(int x) { this.x = x; + rn 2.3.4 Metode cu numar variabil de argumente Incepénd cu versiunea 1.5 a limbajului Java, exist posibilitate de a declara metoce care s& primeasck un numér variabil de argumente. Noutatea const’ in folosirea simbolului..., sintaxa unel astfel de metode find: [modificatori] TipReturnat metoda(TipArgumente ... args) args reprezint& un vector avand tipul specificat si instantiat cu un numér variabil de argumente, in functie de apelul metodei, Tipul ergumentelor poate fi referinté sau primitiv. Metoda de mai jos afigeazi argumentele prim- ite, care pot fi de orice tip: void metoda(Object ... args) { for(int i-0; isargs.length; i++) System. out.println(args[i]) ; } metoda("Hello") ; netoda("Hello", "Java", 1.5); 23, IMPLEMENTAREA METODELOR, 57 2.3.5 Supraincarcarea si supradefinirea metodelor Supraincircatea gi supradefinitea metodelor sunt dou concepte extrem de utile ale programérii orientate obiect, cumoscute si sub denumirea de polimor- fis, si se refer’ ln: © supraincarcarca (overloading) : in cadrul unei clase pot exista metode cu acelagi nume cu conditia ca signaturile lor sa fie diferite (lista de argumente primite s& difere fie prin num&rul argumentelor, fie prin tipul lor) astfel incat la apelul functiei cn acel nume sk se poati sbabili in mod unie care dintre ele se executi © supradefinirea (overriding): 0 subclasi ponte rescrie o metod a cla- sei parinte prin implementarea unei metode cu acelagi nume si aceeasi signatura ca ale superclasei class A { void metoda() { System.out.printIn("A: metoda fara parametru") ; + // Supraincarcare void metoda(int arg) { System.out.println("A: metoda cu un parametru") ; } 3 class B extends A { // Supradefinire void metoda() { System.out.println("B: metoda fara parametru") ; } } O metod supradefiniti poate si © ignore complet codul metodei corespunzitoare din superclass (cazul de mai sus) Bb = new BQ); b.metoda() ; // kfiseaza "B: metoda fara parametru" 58 CAPITOLUL 2. OBIECTE $I CLASE # extindd codul metodei plirinte, executand inainte de codul propriu si functia pirintelui: class B extends A { // Supradefinire prin extensie void metoda() { super .metoda() ; Systen.out.printin("B: metoda fara parametru") ; + + B b = new BQ); b.metoda() ; /* fiseaza ambele mesaje "A: metoda fara parametru" "B: metoda fara parametru" */ © metoda nu poate supradefini o metoda declarat® finalA in clasa pirinte Orice clasé care nu este abstract trebuie obligatorin s8 supradefineasc’ metodele abstracte ale superclasei (dack este cazul). In cazul in care o clasit nu supradefineste toate metodele abstracte ale piintelui, ea insisi este ab- stractii i va trebui declaratii ca atare. In Java nu este posibila supraincirearea operatorilor. 2.4 Modificatori de acces Modificatorii de acces sunt cuvinte rezervate ce controleazi accesul celor- late clase la membrii unei clase. Specificatorii de acces pentru variabilele si metodele unei clase sunt: publi, protected, private si cel implicit (la nivel ce pachet), iar nivelul lor de acces este dat in tabelul ce mai jos: Specificator | Clhsa | Sublasa | Pachet | Orunde private x protected |X x* x public X x X X implicit x x 25, MEMBRI DE INSTANTA $I MEMBRI DE CLASA 59 Agadar, dack mu este specificat nici un modifieator de acces, implicit nivelul de acces este la nivelul pachetului. In cazul in care declar’im un membru” protected” atunci accesul la acel membru este permis din subclasele clasei in care a fost declarat dar depinde si de pachetul in care se gaseste subclasa; dacé, sunt in acelasi pachet accesul este permis, daci nu sunt in acelagi pachet accesul nu este permis decat pentru obiecte de tipul subclasei Exemple de declaratit private int secretPersonal; protected String secretDeFamilie; public Vector pentruToti; long doarIntrePrieteni; private void metodalnterna(); public String informatii() ; 2.5 Membri de instant& gi membri de clas& clas Java poate contine doui tipuri de variabile si metode © de instanfiz declarate far& modificatorul static, specifice fiecirel instante create dintr-o clasit gi © de clasit declarate cu modificatorul static, specifice clasei 2.5.1 Variabile de instanta si de clas& Cand declarim o variabil’ membré fir’ modificatorul static, cum ar fix in exemplul de mai jos: class Exemplu { int x ; //variabila de instanta + se declara de fapt o variabila de instant, ceea ce inseamnti ck la fiecare creare a unui obiect, al clasei Exemplu sistemul aloci o zonii de memorie separatt pentru memorarea valorii Ini x Exemplu o1 = new Exemplu() ; ol.x = 100; 60 CAPITOLUL 2. OBIECTE $I CLASE Exemplu 02 = new Exemplu(); 02.x = 200; System.out.println(o1.x); // Afiseaza 100 System.out.printIn(02.x); // Afiseaza 200 Agadar, fiecare obiect now creat: va putea memora valori diferite pentru variabilele sale de instants. Pentru variabilele de clasa (statice) sistemul aloc® o singur zon’ de m orie Ia care an acces toate instantele clasei respective, cea ce inseamnna ci daci un obiect modifick valoarea unei variabile statice ea se va modifica si pentru toate celelalte obiecte. Deoarece nu depind de o anumiti instant a unei clase, variabilele statice pot fi referite si sub forma: NumeCLasa numeVariabilaStatica class Exemplu { int x ; // Variabila de instanta static long n; // Variabila de clasa 3 Exemplu o1 = new Exemplu() ; Exemplu 02 = new Exemplu(); ot.n = 100; System.out.println(02.n) ; // Afiseaza 100 o2.n = 200; System.out.printin(o1.n); // iseaza 200 System.out.printin(Exemplu.n); // Afiseaza 200 // on, 02.n si Exemplu.n sunt referinte la aceeasi valoare Initializarea variabilelor de clasi se face o singuri dati, la inclircarea in memorie a clasei respective, si este realizat& prin atribuiri obisnuite: class Exempla { static final double PI = 3.14; static long nrInstante = 0; static Point p = new Point(0,0); 3 25, MEMBRI DE INSTANTA $I MEMBRI DE CLASA 61 2.5.2 Metode de instanta gi de clas Similar ca la variabile, metodele declarate fir. modificatorul static sunt metode de instant iar cele declarate cu static sunt metode de clasa (stat- ice). Diferenta intre cele dou’ tipuri de metode este urmitoares: metodele de instanti opereazii atat pe variabilele de instanta cat si pe cele statice ale clasei; # metodele de clas opereaz doar pe variabilele statice ale clasei class Exemplu { int x // Variabila de instanta static long n; // Variabila de clasa void metodaDeInstanta() { n+; // Corect x--; // Corect 3 static void metodaStatica() { n++; // Corect x--; // Eroare la compilare ! 3 } Intocmai ca si la vatiabilele statice, intrucit metodele de clasit nu depind de starea obiectelor clasei respective, apelul lor se poate face gi sub forma: NumeClasa numeMetodaStatica Exemplu.metodaStatica(); // Corect, echivalent cu Exemplu obj = new Exemplu(); obj metodaStatica() ; J/ Corect, de asemenea Metodele de instant nu pot fi apelate decdt pentru un obiect al clasei respective: Exemplu.metodaDeInstanta(); // Eroare la compilare | Exemplu obj = new Exemplu(); obj .metodaDeInstanta() ; // Corect 62 CAPITOLUL 2. OBIECTE $I 2.5.3 Utilitatea membrilor de clas& Membrii de clasit sunt folositi pentru a pune la dispozitie valori si metode independente de starea obiectelor dintr-o anumita clasé. Declararea eficienta a constantelor Sa considerim situatia cind dorim s& declaram o constanté. class Exemplu { final double PI = 3.14; // Nariabila finala de instanta 3 La fiecare instantiere a clasei Exemplu va fi rezervatit o zonii de memorie pentru variabilele finale ale obiectului respectiv, cea ce este o risipé intrucat aceste constante au aceleasi valori pentru toate instantele clasei. Declararea corecti a constantelor trebuie asadar facuti cu modificatorii static sifinal, pentru a le rezerva 0 singuri zon de memorie, comun’ tuturor obiectelor class Exemplu { static final double PI = 3.14; // Nariabila finala de clasa 3 Numiararea obiectelor unei clase Numararea obiectelor unei clase poate fi facuta extrem de simplu folosind variabili static’ si este utili in situatiile cand trebuie si controlam diversi parametri legati de crearea obiectelor unei clase. class Exemplu { static long orInstante = Exemplu() { // Constructorul este apelat la fiecare instantiere nrInstante ++; + 3 25, MEMBRI DE INSTANTA $I MEMBRI DE CLASA 63 Implementarea functiilor globale Spre deosebire de limbajele de programare procedurale, in Java nu putem avea functii globale definite ca atare, intrucat "orice este un obiect”, Din acest motiv chiar si metodele care au o functionalitate globalé trebuie im- plementate in cadrul unor clase, Acest Iucru se va face prin intermediul metodelor de clas (globale), deoarece acestea nu depind de starea partic- ular a obiectelor din clasa respectivé. De exemplu, si consider’im funetia sqrt care extrage radicalul unui numir si care se giseste in clasa Math. Dac& nit ar fi fost functie de clas, apelul ei ar fi trebuit fiicut astfel (incorect, de altfel) // Incorect ! Math obj = new Math(); double rad = obj.sqrt (121) ; cea ce ar fi fost extrem de neplitcut... Flind ins metodii statics ea poate fi apelat prin: Math.sqrt (121) . Asadar, functiile globale necesare unei aplicatii vor fi grupate corespunzittor in diverse clase si implementate ca metode statice. 2.5.4 Blocuri statice de initializare Variabilele statice ale unei clase sunt initializate la un moment care precede prima utilizare activi a clasei respective. Momentul efectiv depinde de im- plementarea masinii virtuale Java $i poartt’ numele de inifializarea clase. Pe lang setarea valorilor variabilelor statice, in aceastit etapi sunt executate si blocurile statice de initializare ale clasei. Acesten sunt secvente de cod de forma: static { // Bloc static de initializare; + care se comport ca 0 metodi statici apelatii automat de citre magina vir- tuali. Variabilele referite intr-un bloc static de initializare trebuie s& fie obligatoriu de clasit sau locale blocului: public class Test { // Declaratii de variabile statice 64 CAPITOLUL 2. OBIECTE $I static int x= 0, y, 2; // Bloc static de initializare static { System. out.printin("Initializam..."); int t-1; y= 2; zextytt; + Test) { /* La executia constructorului variabilele de clasa sunt deja initializate si toate blocurile statice de initializare au fost obligatoriu executate in prealabil. */ 2.6 Clase imbricate 2.6.1 Definirea claselor imbricate O claséi imbricattieste, prin definitie, o clas’ membri a unel alte clase, numiti si clasié de acoperire. In functie de situatie, definirea unei clase interne se poate face fie ca membru al clasei de acoperire - caz in care este accesibili tuturor metodelor, fie local in cadrul unei metode class ClasaDeAcoperire{ class Clasalmbricatal { // Clasa menbru + void metoda() { class Clasalmbricata2 { // Clasa locala metodei + + 2.6, CLASE IMBRICATE 65 + Polosirea claselor imbricate se face atunci cand o clasit are nevoie in im- plementarea ei de o alti clasa si nu exista nici un motiv pentru care aceasta din urma si fie declarat de sine stitatoare (nu mai este folosité niciieri) clasit imbricatié are un privilegiu special fat de celelalte clase si anume acces nerestrictionat la toate variabilele clasei de ncoperite, chiar dack aces- tea sunt private. O clasi declarata local unei metode va avea acces si la variabilele finale declarate in metoda respectiva. class ClasaDeAcoperire{ private int x=1; class Clasalmbricatal { int asx; + void metoda() { final int y-2; int 3 class Clasalmbricata2 { int b=x; int c=y; int d=z; // Incorect + } } O clas imbricati membr& (care nu este localé unei metode) poate fi referitii din exteriorul clasei de acoperire folosind expresia ClasaDeAcoperire.Clasalmbricata Agadar, clasele membru pot fi declarate cu modificatorii public, protected, private pentru a controla nivelul lor de acces din exterior, intocmai ca orice variabila sau metod’ mebri a clasei. Pentru clasele imbricate locale unei metode nu sunt permisi acesti modificatori. ‘Toate clasele imbricate pot fi declarate folosind modifieatorii abstract gi final, semnificatia lor fiind aceeasi ca gi in cazul claselor obignuite. 66 CAPITOLUL 2. OBIECTE $I 2.6.2 Clase interne Spre deosebire de clasele obignnite, o clas’ imbricat poate fi declarati static san ni, O clas imbricata nestatick se numeste clasa interna. class ClasaDeAcoperire{ class Clasalnterna { } static class ClasalmbricataStatica { + 3 Diferentierea acestor denumiri se face deoarece: ¢ 0 "clasit imbricati” reflectit relatia sintactici a dout{ clase: codul unei clase apare in interiorul codului altel clase; ¢ 0 clasi intern” reflect relatia dintre instantele a dou clase, in sensul ci o instanta a unci clase interne nu poate cxista decat in cadrul unci instante a clasei de acoperire. In general, cele mai folosite clase imbricate sunt cele interne, Asadar, o clasi intern este o clas imbricati ale carei instante nu pot. exista decat in cadrul instantelor clasei de acoperire si care are acces direct la toti membrii clasei sale de acoperire. 2.6.3 Identificare claselor imbricate Dupi cum stim orice clasi produce la compilare aga numitele ” unititi de com- pilare”, care sunt fisiere avand numele clasei respective si extensia .class si care contin toate informatiile despre clasa respectivé.. Pentru clasele im- bricate aceste unititi de compilare sunt denumite astfel: numele clasei de acoperire, urmat de simbolul ’$’ apoi de numele clasei imbricate. class ClasaDeAcoperire{ class ClasaInternai {} class Clasalnterna2 {} 3 g 2.7, CLASE $I METODE ABSTRACTE 6 Pentru exemplul de mai sus vor fi generate tel fisiere: ClasaDeAcoperire class ClasaDeAcoperire§Clasalnternal .class ClasaDeAcoperire§Clasalnterna2.class In cazul in care clasele imbricate au la réndul lor alte clase imbricate (situate mai putin uznala) denumirea lor se face dup’ aceeagi reguld: ad&ugarea unui ’S’ si apoi numele clasei imbricate. 2.6.4 Clase anonime Exist posibilitatea definitii unor clase imbrieate locale, fir nume, utilizate doar pentru instantierea unui obiect de un anumit tip. Astfel de clase se numesc clase anonime si sunt foarte utile in situatii cum ar fi crearea unor obiecte ce implementeazk o anumiti interfati sau extind o anumité clas abstractis Exemple de folosire a claselor anonime vor fi date in capitolul "Interfete” precum si extensiv in capitolul "Interfata grafic cu utilizatorul” Fisierele rezultate im urma compiliri claselor anonime vor avea numele de forma Clasakcoperire .$1,.... CLasaAcoperire $n, unde neste numéral de clase anonime definite in clasa respectiva de acoperire. 2.7 Clase si metode abstracte Uneori in proiectarea unei aplicatii este necesar sf reprezentlim cu. ajutorul claselor concepte abstracte care si nu poatii fi instantiate si care sii foloseasc doar la dezvoltarea ulterioari a nnor clase ce deserin obiecte concrete. De ex- emplu, in pachetul java. lang exist clasa abstract Number care modeleazit conceptul generic de "numir”, Intr-un program nu avem insi nevoie de nu- mere generice ci de numere de un anumit tip: intregi, reale, ete. ClasaNumber serveste ca superclasi pentru clasele concrete Byte, Double, Float, Integer, Long si Short, ce implementeaza obiecte pentru descrierea numerelor de un. anumit tip. Agedar, clasa Number reprezinti un concept abstract: si nu vorn putea instantia obiecte de acest tip - vor folosi in schimb subclasele sale. new Number); // Broare new Integer (10); // Corect Number numar Integer intreg 68 CAPITOLUL 2. OBIECTE $I 2.7.1 Declararea unei clase abstracte Declararea unei clase abstracte se face folosind cuvantul rezervat abstract: [public] abstract class ClasaAbstracta [extends Superclasa] (implements Interfatai, Interfata2, ...] { // Declaratii uzuale // Declaratii de metode abstracte O clasi abstract poate aven modificatorul public, accesul implicit find la nivel de pachet, dar nu poate specifica modificatorul final, combinatia abstract final fiind semnalatii ca eroare la compilare - de altfel, 0 clasit declarata, astfel nu ar avea nici o utilitate, O clas abstract poate contine aceleasi elemente membre ca o clast obisnuit, la care se adaugt declaratii de metode abstracte - fir nici o im- plementare, 2.7.2 Metode abstracte Spre deosebire de clasele obisnuite care trebuie si furnizeze implementiri pentru toate metadele declarate, o clas abstractil poate contine metode fitrit nici o implementare. Metodele fara nici o implementare se numeso metode abstractesi pot apirea doar in clase abstracte. In fata unei metode abstracte trebuie si apar’ obligatorin cuvantul cheie abstract, altfel va fi furnizata o eroare de compilare. abstract class ClasaAbstracta { abstract void metodadbstracta(); // Corect void metoda() ; // Broare 3 In felul acesta, o clasit abstracts poate pune la dispozitia subclaselor sale tun model complet pe care trebuie sé-] implementeze, furnizind chiar imple mentarea unor metode comune tuturor claselor si lisand explicitarea altora 2.7, CLASE $I METODE ABSTRACTE 69 fieotrei subclase in patte. Un exemplu elocvent de folosire a claselor si metodelor abstracte este de- scrierea obiectelor grafice intr-o manier’ orientati-obiect. © Obiecte grafice: linii, dreptunghinri, cercuri, curbe Bezier, ete © Stiri comune: pozitia(originea), dimensiunea, culoarea, ete ¢ Comportament: mutare, redimensionare, desenere, colorare, etc Pentru a folosi stirile si comportamentele comune acestor obiecte in avan- tajul nostru puter declara o class generic GraphicObject care si fie su- perclasii pentru celelalte clase. Metodele abstracte vor fi folosite pentru im- plementarea comportamentului specific fiectirui obiect, curn ar fi desenarea iar cele obignuite pentru comportamentul comun tuturor, cum ar fi schim- bares originii. Implementarea clasei abstracte GraphicObject ar putea arta astfel: abstract class GraphicObject { // Stari comune private int x, y; private Color color = Color.black; // Metode comune public void setX(int x) { this.x = x; } public void setY(int y) { this.y = y; + public void setColor(Color color) { this.color = color; } // Metode abstracte abstract void draw(); 70 CAPITOLUL 2, OBIBCTE $I CLASE Ossubclasa care mm este abstract a unei clase abstracte trebuie sé furnizeze obligatorin implementiiri ale metodelor abstracte definite in superclasi. Im- plementarea claselor pentru obiecte grafice ar fi class Circle extends GraphicObject { void draw() { // Obligatoriu implementarea + + class Rectangle extends GraphicObject { void draw() { // Obligatoriu implementarea Legat de metodele abstracte, mai trebuie mentionate urmatoarele + 0 clasit abstractt poate sit nu aibi nici o metodit abstractis ¢ 0 metoda abstracti{ nu poate apirea decat intr-o clas abstractis © Orice clasi care are o metodé abstracta trebuie declarati ca fiind ab- stracti In APLul oferit de platforma de Iucru Java sunt numeroase exemple de ierarhii care folosesc la nivelele superioare clase abstracte. Dintre cele mai importante amintim: ¢ Number: superclasa abstractit a tipurilor referint numerice © Reader, Writer: superclasele abstracte ale fluxurilor de intrare/iesire pe caractere ¢ InputStream, OutputStream superclasele abstracte ale fluxurilor de intrare/iegire pe octeti © AbstractList, AbstractSet, AbstractMap: superclase abstracte pen- tru structuri de date de tip colectie 28, CLASA OBJECT 7 © Component : superclasa abstractii a componentelor folosite in dez- voltarea de aplicatii cu interfats grafici cu utilizatorul (GUI), cum ar fi Frame, Button, Label, etc. © ete, 2.8 Clasa Object 2.8.1 Orice clas& are o superclasa Dupi cum am vizut in sectiunea dedicat’ modalititii de creare a unei clase, clauza “extends” specifics faptul c& acea clasé extinde (mogteneste) o alti clas, numité superclasa. O clas poate avea o singuré superclasé (Java nu suport mostenirea multipla) si chiar dacé nu specificdm clauza "extends? la crearea unei clase ea totusi va avea o superclas. Cu alte cuvinte, in Java orice clasi are o superclasi si numai una, Evident, trebuie st existe o exceptie de la aceasta regulit si anume clasa care reprezinti ridiicina ierarhiel format de relatiile de mostenire dintre clase. Aceasta este clasa Object. Clasa Object este si superclasa implicit a claselor care nu specifies o anumita superclass. Declaratiile de mai jos sunt echivalente: class Exemplu {} class Exemplu extends Object {} 2.8.2 Clasa Object Clasa Object este cea mai general dintre clase, orice obiect find, direct sau indirect, descendent al acestei clase. Fiind p&rintele tuturor, Object defineste si implementeaz comportamentul comun al tuturor celorlalte clase Java, cum ar fi © posibilitates testatii egalitatii valorilor obiectelor, © specificarea unei reprezentiri ca sir de caractere a unui obiect , © returnarea clasei din care face parte un obiect, © notificarea altor obiecte co variabila de conditie s-a schimbat, ete. 72 CAPITOLUL 2. OBIECTE $I ASE Fiind subclasé a lui Object, orice clasi ii poate supradefini metodele care nu sunt finale. Metodele cel mai uzual supradefinite sunt: clone, equals/hashCode, finalize, toString. # clone Aceast metodi este folosita pentru duplicarea obiectelor (crearea unor clone). Clonarea unui obiect: presupune crearea unui now obiect de acelagi tip si care sit abi aceeasi stare (aceleasi valori pentru variabilele sale) equals, hashCode Acestea sunt, de obicei, supradefinite impreuni, In metoda equalseste scris codul pentru compararea egalititii continutului a dou obiecte. Implicit (implementarea din clasa Object), aceast metod’ compard referintele obiectelor. Uzual este redefiniti pentru a testa daci stirile obiectelor coincid sau daci doar o parte din variabilele lor coincic. Metoda hashCode returneaza un cod intreg pentru figcare obiect, pen- tru a testa consistenta obiectelor: acelasi obiect trebuie sk returneze acelasi cod pe durata executiei programulti Dacié douit obiecte sunt egale conform metodei equals, atunci apelul mnetodei hashCode pentru fiecare din cele dow’ obiecte ar trebui si returneze acelasi intreg, * finalize In aceasti metods se serie codul care ”onr’t dup& un obiect” inainte de a fi eliminat din memorie de colectorul de gunoaie. {vezi ” Distrugerea obiectelor”) © toString Este folosit pentru a returna o reprezentare ca sir de caractere a unui obiect. Este utilé pentru concatenarea sirurilor cu diverse obiecte in vederea afisiti, fiind apelati, automat atunci cand este necesarii trans- formarea unui obiect in sit de caractere. Exemplu obj = new Exemplu() ; System.out.printin("Obiect=" + obj); /fechivalent cu System.out.println("Obiect=" + obj .toString()) ; 28, CLASA OBJECT 73 S& consideriim urmitorul exemplu, in care implomentiim partial clasa numerelor complexe, si in care vom supradefini metode ale clasei Object. De asemenea, vom serie un mic program TestComplex in care vom testa metodele clasei definite clase Complex ¢ private double a; //partea reala private double b; //partea tmaginara public Complex (double a, double b) { this.a = a; this.b = b; + public Complex() { this(1, 0); + public boolean equals (Object obj) ¢ if (obj == null) return false: if (1(obj instanceof Complex)) return false: Complex comp = (Complex) obj; return ( comp.as=a &t comp. >: oH + public Object clone() { return new Complex(a, b); } public String toString() { String conn = (b> 0 7 "# retura a + semn +b + "i" + public Complex aduna(Complex comp) { Complex suma = new Complex(0, 0); suma.a = this.a + comp.a; suma.b = this.b + comp.bj return suma; 74 CAPITOLUL 2. OBIECTE $I CLASE public class TestComplex { public static void main(String c[l) { Complex ci = new Complex(1,2); Complex c2 = new Complex (2,3); Complex c3 = (Complex) c1.clone(); Systen.out .printin(c1.aduna(c2)); | // 3.0 + 5.0% System. out.printin(c1.equals(c2)); // false System. out printin(ci.equals(c3)); // true 2.9 Conversii automate intre tipuri Dupi cum vizut tipurile Java de date pot fi impittie in primitives referinti Pentru fiecare tip primitiv exists o clas corespunzittoare care permie lucrul orientat obiect cu tipul respectiv. byte [Byte short | Short int Integer Tong | Long Float [Float double [Double char | Character boolean | Boolean Ficcare din aceste clase are un constructor ce permite initializarea unui obiect avand o anumiti valoare primitiva si metode specializate pentru con- versia unui obiect in tipul primitiv corespunzittor, de gemul tipPrimitiWa Lue: Integer obi = new Integer(1); int i = obi.intValue(); Boolean obb = new Boolean(true) ; boolean b = obb.booleanValue(); Incepénd cu versiunea 1.5 a limbajului Java, atribuirile explicite intre tipuri primitve si referinta sunt posibile, acest mecanism purtand numele de autoboring, vespectiv auto-unboring Conversia explicit va fi facutil de catre compilator 2.10. TIPUL DE DATE ENUMERARE 75 // Doar de 1a versiunea 1.5 | Integer obi = 1; int i = obi; Boolean obb = true; boolean b = obb; 2.10 Tipul de date enumerare Incepand ou versiunea 1.5 a limbajului Java, exist posibilitatea de a defini tipuri de date enumerare prin folosirea cuvantului cheie enum. Aces solutie simplifics manevrarea grupurilor de constante, dup’ cum reiese din urmitorul exemplu: public class CuloriSemafor { public static final int ROSU = public static final int GALBEN public static final int VERDE } // Exemplu de utilizare if (semafor.culoare = CuloriSemafor.ROSU) senafor.culoare = CuloriSemafor .GALBEN) ; Clasa de mai sus poate fi rescrisa astfel: public enum CuloriSemafor { ROSU, GALBEN, VERDE }; // Utilizarea structurii se face la fel if (semafor.culoare = CuloriSemafor.ROSU) semafor.culoare = CuloriSemafor..GALBEN) ; Compilatorul este responsabil cu transformarea unel astfel de structuri ‘intr-o clas’ corespunzittoare CAPITOLUL 2. OBIECTE $I CLASE Capitolul 3 Exceptii 3.1. Ce sunt exceptiile ? ‘Termenul excepticeste o prescurtare pentru “eveniment exceptional” gi poate fi definit ca un eveniment ce se produce in timpul executiei unui program si care provoact intreruperea cursului normal al executiei acestiuia. Exceptiile pot apirea din diverse cauze si pot avea nivele diferite de grav- itate: de la erori fatale cauzate de echipamentul hardware pani la erori ce tin strict de codul programului, cum ar fi accesarea unui element din afara spatiului alocat unui vector. In momentul cand o asemenea eroare se produce in timpul executiel va fi generat un obiect de tip exceptie ce contine: © informatii despre exceptia respectivi; © starea programului in momentul producerii acelei excepti public class Exemplu { public static void main(String args(]) { int v[] = new int [10]; v[10] = 0; //Exceptie ! System.out.printIn("Aici nu se mai ajunge..."); + } La rularea programului va fi generat o exceptie, programul se va opri la instructiunea care a cauzat exceptia si se va afiga un mesaj de eroare de genul: a 78 CAPITOLUL 3. EXCEPTIL “Exception in thread "main" java. lang. ArrayIndexDut0fBoundsException :10 at Exceptii.main (Exceptii.java:4)" Crearea unui obiect de tip exceptie se numeste aruncarea unei exceptii (throwing an exception”). In momentul in care o metod genereazi, (arunes) © exceptie sistemul de executie este responsabil cu gisirea unei seevente de cod dinti-o metodit care si o trateze. Cautarea se face recursiv, incepand cu metoda care a generat exceptia si mergénd inapoi pe linia apelurilor cétre acea metoda. Seeventa de cod dintr-o metodi care trateazi o anumiti exceptie se numegte analizor de exceptic (” exception handler”) iar interceptarea si tratarea ei se numeste prinderea exceptici ("catch the exception”) Cu alte cuvinte, la aparitia unei erori este "aruncati” o exceptie iar cineva trebuie si o “prind’” pentru a o trata. Daci sistemul nu gaseste nici un analizor pentru o anumité exceptie, atunei programul Java se opreste cu un mesaj de eroare (in cazul exemplului de mai sus mesajul ”Aici nu se mai ajunge...” nu va fi afigat) Atentie In Java tratarea erorilor nm mai este 0 optiune ci o constrangere. In aproape toate situatile, o secventi de ood care poate provoca exceptii trebuie si specifice modalitatea de tratare a acestora. 3.2. ”Prinderea” si tratarea exceptiilor ‘Tratarea exceptiilor se realizeaz’i prin intermediul blocurilor de instructiuni try, catch gi finally. O secventi de cod care trateazi anumite exceptii trebuie sii arate astfel try { // Instructiuni care pot genera exceptii } catch (TipExceptiel variabila) { // Tratarea exceptiilor de tipul 1 3.2. "PRINDEREA” SI TRATAREA EXCEPTIULOR 79 + catch (TipExceptie2 variabila) { // Tratarea exceptiilor de tipul 2 + finally { // Cod care se executa indiferent // daca apar sau nu exceptii } S& consider urmittorul exemplu: citirea unui fisier octet cu octet si afisarea lui pe ecran, Pari a folosi tratarea exceptillor metoda responsabili cu cititea fisierului ar arta astfel: public static void citesteFisier(String fis) { FileReader f = null; // Deschidem fisierul System.out.printIn("Deschidem fisierul " + fis); f = new FileReader (fis) ; // Citim si afisam fisierul caracter cu caracter int ¢; while ( (c-f.read()) != -1) System.out.print ((char)c) ; // Inchidem fisierul System.out.printin("\\nInchiden fisierul " + fis); f.close(); } Aceaatis seeventé de cod va furniza erori la compilare deoarece in Java tratarea erorilor este obligatorie. Folosind mecanismul exceptillor metoda citeste isi poate trata singurd erorile care pot surveni pe parcursul executiei sale. Mai jos este codul complte gi corect al unui program ce afigeazi pe ecran continutul unui fisier al c&rui nume este primit ca argument de la linia de comandi, ‘Tratarea exceptiilor este realizat complet chiar de clitre metoda citeste, 80 CAPITOLU 3. EXCEPTIL Listing 3.1: Citirea unui fisier - corect import java.io.*; public class CitireFisier { public static void citesteFisier (String fis) ¢ FileReader f = null; try ¢ // Deschiden fisterul Systom.out.printin("Deschidem fisierul * + fis); f = new FileReader (fis) ; // Citim si afisom fisterul caracter cu caracter int ci while ( (c=f.read()) != -1) System. out. print ((char)c) ; } catch (FileNotFoundException ©) { //Tratan un tip de exceptie Systen.err.println("Fisierul au a fost gasit !"); Systen.err.printIn("Exceptie: " + e.getHessage()); Syaten. exit (1); } catch (IOException e) { //Tratam alt tip de exceptie Syetem.out.printin("Eroare la citirea din fisier!") e. printStackTrace (); } finally ¢ if ( '= nul) ¢ // Inchidem fisterut System.out .printin("\nInchidem fisierul."); try ¢ f£.closeQ; } catch (IOException ©) { System.err.printin("Fisierul nu poate fi inchis!"); e.printStackTrace(); 3 3 + public static void main(String args[]) { if (args.length > 0) oFisier (args [0]) ; 3.2, "PRINDEREA” SI TRATAREA EXCEPTULOR: 81 Systom.out.println("Lipseste numele fisierului! Blocul ”try” contine instructiunile de deschidere a unui fisier gi de citire dintr-un fisier, ambele putind produce exceptli. Exceptiile provocate de aceste instructiuni sunt tratate in cele dou’ blocuri “catch”, cate unul pen- tru fiecare tip de exceptie. Inchiderea figierului se face in blocul “finally”, deoarece acesta este sigur ci se va executa Pir’ a folosi blocul “finally”, inchideres fisierului ar fi trebuit facut in fiecare situatie in care fisierul ar fi fost deschis, ceea ce ar fi dus Ia scrierea de cod redundant. try { // Totul a decurs bine f.close(); + catch (I0Exception e) { // A aparut o exceptie la citirea din fisier f.close(); // cod redundant } © problemi mai delicatit care trebuie semmalata in aceasta situatie este faptul ck metoda close, responsabilli cu inchiderea unui fisier, poate provoca Ja randul siu exceptii, de exemplu atunci cind figierul mai este folosit si de alt proces si nu poate fi iuchis. Deci, pentru a avea un cod complet corect trebuie sii tratiim si posibilitaten aparitiei unei exeeptii la metoda close. Atentie Obligatorin un bloc de instructiuni "try” trebuie si fie urmat de unul sau mai multe blocuri ”catch”, in functie de exceptille provocate de acele instructiuni sau (optional) de un bloc "finelly” 82 CAPITOLU 3. EXCEPTIL 3.3 ” Aruncarea” exceptiilor In cazul in care o metodi nu isi asumi responsabilitatea tratril uneia sau mai multor exceptii pe care le pot provoca anumite instructiuni din codul siu atunci ea poate si "arunce” nceste exceptil citre metodele care 0 ape- leazi, urménd ca acestea sé implementeze tratarea lor sau, la randul lor, si “arunce” mai departe exceptiile respective. Acest Iucru se realizeazii prin specificarea in declaratia metodei a clauzel throws: (nodificatori] TipReturnat metoda([argumente]) throws TipExceptiel, TipExceptie2, .. { + Atentie © metoda care nu trateazit o anumiti exceptie trebuie obligatorin si o *arunce”. In exemplul de mai sus dack nu facem tratarea exceptillor in cadrul metodei citeste atunei metoda apelantit (main) va trebui sé faci acest, Incru: Listing 3.2: Citirea unui fisier import java.io. *; public class CitireFisier { public static void citesteFisier (String fis) throws FilellotFoundException, IOException { FiloReader f = null; £ = new FileReader (fis); int ¢; while ( (c=f.read()) != -1) System. out. print ((char)c); f.close(); 3.3. ARUNCAREA” EXCEPTIILOR 83 public static void main(String args[]) ¢ if (arge.length > 0) ¢ try { citesteFisier (args [0]) ; } catch (FileNotFoundException e) { System.err.printIn("Fisierul nu a fost gasit !"); System.err.printin("Exceptie: " + €)j } cateh (10Exception e) { System. out. printin("Eroare la citirea din fisier!"); ©. printStackTrace(); } } else Systom.out.printla("Lipseste numele fisierului Observati eX, in acest caz, nu mai putem diferentia exceptiile provocate de citirea din fisier s de inchiderea fisierului, ambele fiind de tipul IOException. De asemenea, inchiderea fisierulul mu va mai fi facut in situatia in care apare o exceptie la citirea din fisier. Este situatia in care putem folosi blocul finally fird a folosi nici un bloc catch: public static void citesteFisier(String fis) throws FileNotFoundException, IOException { FileReader f = null; try { f = new FileReader(numeFisier) ; int ¢; while ( (c=f.read()) I= -1) System.out .print((char)c) ; + finally { if (f!=null) f.close(); 84 CAPITOLUL 3. EXCEPTIL Metoda apelantii poate arunca la randul sau exceptille mai departe citre metoda care a apelat-o la randul ei. Aceastii inlantuire se termini cu metoda main care, dack va arunea exceptille ce pot aplirea in corpul ei, va determina trimiterea exceptiilor ciitre magina virtuala Java. public void metoda3 throws TipExceptie { + public void metoda2 throws TipExceptie { metoda3() ; + public void metodal throws TipExceptie { metoda2() ; + public void main throws TipExceptie { metodal () ; + ‘Tratarea excepiiilor de clitre JVM se face prin terminarea programului si afigarea informatillor despre exceptia care a determinat acest Iueru, Pentru exemplul nostru, metoda main ar putea fi declarata astfel: public static void main(String args[]) throws FilellotFoundException, IOException { citeste(args[0]); + Intotdeauna trebuie gésit compromisul optim intre tratarea local a exceptiilor si aruncarea lor citre nivelele superioare, astiel ineat codul si fie cat mai clar si identificarea locului in care a aprut exceptia si fie cat mai ugor de facut Arunearea unei exceptii se poate face si implicit prin instructiunea throw ce are formatul: throw exceptie, ca in exemplele ce mai jos throw new IDException("Exceptie 1/0"); if (index >= vector. length) throw new ArrayIndexOut0fBoundsException() ; 34, AVANTAJELE TRATARIL EXCEPTHULOR 85 catch(Exception e) { System.out.println("A aparut o exceptie) ; throw e; + Aceastif instructiune este folosita mai ales la aruncarea exceptiilor proprii (vezi ”Crearea propriilor except”) 3.4 Avantajele tratarii exceptiilor Prin modalitatea sa de tratare a exceptiilor, Java are urmitoarele avantaje fatii de mecanismul traditional de tratare a etorilor: © Separarea codului pentru tratares tnei erori ce codul in care ea poate sé apari, © Propagerea unei erori pana la. un analizor de exceptii corespunzator © Gruparea erorilor dupé tipul lor 3.4.1 Separarea codului pentru tratarea erorilor In programarea traditionali tratarea erorilor se combini cu codul ce poate produce aparitia lor producdnd asa numitul *cod spaghetti”. Si consider’ urmitorul exemplu; o functie care incarcé un fisier in memorie: citesteFisier { deschide fisierul; determina dimensiunea fisierului; aloca memorie; citeste fisierul in memorie; inchide fisierul; Problemele care pot aplirea la aceasta functie, aparent simpl&, sunt de genul: "Ce se intampla dacit: ... 2” ¢ figierul nu poate fi deschis # nu se poate determina dimensiunea fisierului 86 CAPITOLUL 3. EXCEPTID ¢ nu poate fi alocatit suficient memorie ¢-nu se poate face citirea din fisier ¢ figierul nu poate fi inchis Un cod traditional care si trateze aceste erori ar arita astfel: int citesteFisier() { int codEroare = 0; deschide fisierul; if (fisierul s-a deschis) { determina dimensimea fisierului; if (s-a determinat dimensiunea) { aloca memorie; if (s-a alocat memorie) { citeste fisierul in memorie; if (nu se poate citi din fisier) { codEroare = + } else { codEroare = -2; } y else { codEroare = + inchide fisierul; if (Zisierul nu s-a inchis && codEroare codEroare } else { codEroare + } else { codEroare = + return codEroare; + // Cod "spaghetti" Acest stil de progamare este extrem de susceptibil la etori gi ingreumeazit extrem de mult inttelegerea sa. In Java, folosind mecansimul exceptiilor codul ar arata, schematizat, astfel: 3.4, AVANTAJELE TRATARIL EXCEPTILOR 87 int citesteFisier() { try { deschide fisierul; determina dimensiunea fisierului; aloca menorie; citeste fisierul in memorie; inchide fisierul; catch (fisierul nu s-a deschis) {trateaza eroarea;} catch (nu s-a determinat dimensiunea) {trateaza eroarea;} catch (nu s-a alocat memorie) {trateaza eroarea} catch (nu se poate citi din fisier) {trateaza eroarea;} catch (nu se poate inchide fisierwl) {trateaza eroarea;} 3 Diferenta de claritate este evident. 3.4.2 Propagarea erorilor Propagarea unei erori se face pant la un analizor de exceptii corespunzator. SA presupunem ci apelul la metoda citesteFisier este consecinta unor apeluri imbricate de metode int metodal({) { metoda2() ; + int metoda2() { metoda3; + int metoda3 { citesteFisier() ; 88 CAPITOLUL 3. EXCEPTIL + $i presupunem de asemenea ci dorim sii facem tratarea erorilor doar inmetodal. Traditional, acest Iucru ar trebui facut prin propagarea erorli produse de metoda citesteFisier pani lametodat: int metodal() { int codEroare = metoda2(); if (codEroare != 0) //proceseazaEroare ; + int metoda2() { int codEroare = metoda3() ; if (codEroare != 0) return codEroare; + int metoda3() { int codEroare = citesteFisier() ; if (codEroare != 0) return codEroare ; + Dupé cum am vazut, Java permite unei metode si arunce exceptiile aplute in cadrul ei la un nivel superior, adick functiilor care o apeleazt sau sistemului, Cu alte cuvinte, 0 metodis poate si nu isi asume responsabil- itatea tratirii exceptiilor apirute in cadrul ei: int metodal() { try { metoda2() ; } catch (TipExceptie e) { /[proceseazabroare; r + 34, AVANTAJELE TRATARIL EXCEPTHULOR 80 int metoda2() throws TipExceptie { metoda3() ; + int metoda3() throws TipExceptie { citesteFisier(); } 3.4.3 Gruparea erorilor dup tipul lor In Java exist clase corespunzittoare tuturor exceptiilor care pot apitrea la executia unui program. Acestea sunt grupate in functie de similaritittile lor intr-o ierarhie de clase. De exemplu, clasa IOException se ocupi en exceptiile ce pot apitea la operatii de intrare/iesire si diferentiaza la randul ei alte tipuri de exceptii, cum ar fiFileNotFoundException, EOFException, ete La randul ei, clasa IOException se incadreazit intt-o categorie mai larg’ de exceptii si anume clasa Exception. Radacini acestei ierarhii este clasa Throwable (vezi “Ierarhia claselor ce de- scriu exceptii”) Pronderea unei exceptii se poate face fie la nivelul clasei specifice pen- tru acea exceptie, fie la nivelul uneia din superclasele sale, in functie de necesitiitile programului, insi, cu cat clasa folositi este mai generic cu atat tratarea exceptiilor programul isi pierde din flexibilitate. try { FileReader f = new FileReader("input dat") ; /* Acest apel poate genera exceptie de tipul FilelotFoundException Tratarea ei poate fi facuta in unul din modurile de mai jos: */ } catch (FileNotFoundException e) { // Exceptie specifica provocata de absenta // fisierului ‘input dat? 3 // sau 90, CAPITOLUL 3. EXCEPTID catch (IOException e) { // Exceptie generica provocata de o operatie 10 3 // sau catch (Exception e) { // Coa mai generica exceptie soft 3 //sau catch (Throwable e) { // Superclasa exceptiilor + 3.5 Terarhia claselor ce descriu exceptii Riidacina claselor ce descriu except este clasa Tarowable iar cele mai impor- tante subclase ale sale sunt Error, Exception si RuntimeException, care sunt la randul lor superclase pentru o serie intreagit de tipuri de exceptii Throwable Enver Exception RuntimeException 1OException J | a FilolletFoundException Frorile, obiecte de tip Error, sunt cazuri speciale de exceptii generate de functionarea anormal a echipamentului hard pe care ruleazi un pro- gram Java si sunt invizibile programatorilor. Un program Java nu trebuie si trateze aparitia acestor erori si este improbabil ca.o metods Java s& provoace asemenea erori 3.6, EXCEPTI LA EXECUTIE a1 Exceptiile, obiectele de tip Exception, sunt exceptiile standard (soft) care trebuie tratate de citre programele Java. Dup& cum am mai zis tratarea aces tor exceptii nu este o optiune ci o constrangere. Exceptiile care pot *sciipa” netratate descind din subclasa RuntimeException si se numese exceptit la execute, Metodele care sunt apelate uzual pentru un obiect exceptie sunt definite in clasa Throwable si sunt publice, astfel incdt pot fi apelate pentru orice tip de exceptie. Cele mai uzuale sunt: © gotMessage - afigeazli detaliul unei exceptit; © printStackTrace - afigeazi informatii complete despre exceptie si lo- calizarea ei; © toString- metodé mostenita din clasa Object, care furnizenzi reprezentarea ca sir de caractere a exceptiei 3.6 Exceptii la executie In general, tratarea exceptiilor este obligatorie in Java. De la acest principuse sustrag insi aga numitele excepfit la evecufie san, cu alte cuvinte, exceptiile care provin strict din vina programatorului si nu generate de o anumiti situatie extern’, cum ar fi lipsa unui fisier. Aceste exceptii au o superclasi comuni RuntimeException si in acesata categorie sunt incluse exceptiile provocate de: © operatii aritmetice ilegale (impartitea intregilor le zero); ArithmeticException # accesarea membrilor unui obiect ce are valoarea nul]; Yul 1PointerException # accesarea eronati a elementelor unui vector ArrayIndexOutOfBoundsException Exceptiile la executie pot aptirea uriunde in program si pot fi extrem de numeroare iar incercarea de "prindere” a lor ar fi extrem de anevoioasi. Din acest motiv, compilatorul permite ca aceste exceptii si ramank netratate, tratarea lor nefiind insi ilegalii. Reamintim insi ci, in cazul aparitiei oricsrui tip de exceptie care nu are un analizor corespunaiitor, prograrmul va fi termi- nat. 92 CAPITOLUL 3. EXCEPTIL int v(] = new int[10]; try { v[10] = 0; } catch (ArrayIndexOutfBoundsException e) { System.out.println("Atentie la indecsi!"); e.printStackTrace() ; 3 // Corect, programul continua v(t] = 0; /+ Wu apare eroare 1a compilare dar apare exceptie la executie si programul va fi terminat. */ System.out.printIn("Aici nu se mai ajunge. 5 Impittirea la 0 va genera o exceptie doar dact tipul numerelor impirtite este aritmetic intreg. In cazul tipurilor reale (£loat si double) nu va fi generatit nici o exceptie, ci va fi furnizat ca rezultat constant care poate fi, functie de operatie, Infinity, -Infinity, sau Nan. int ast, int b-0; System.out.println(a/b); // Exceptie la executie ! double x=1, y=-1, 2-0; System.out.println(x/z); // Infinity System.out.printin(y/z); // -Infinity System.out.printin(z/z); // Nal 3.7 Crearea propriilor exceptii Adeseori poate apiirea necesitatea credrii unor exceptii proprii pentru a pune inevidenta cazuri speciale de erori provocate de metodele claselor unel libra, cazuri care nu aul fost prevazute in ierarhia exceptillor standard Java, exceptie proprie trebuie sii se incadreze insit in ierarhia exceptillor Java, cu alte cuvinte clasa care o implementeaz’s trebule si fie subclasi a uneia deja existente in aceasta ierarhie, preferabil una apropiati ca semnificatie, sau superclasa Exception. 3.7, CREAREA PROPRIILOR EXCEPTII O83 public class ExceptieProprie extends Exception { public ExceptieProprie(String mesaj) { super (mesaj) ; // bpeleaza constructorul superclasei Exception + + Sé considerim urmittorul exemplu, in care creim o clasi ce deserie partial o stiva de numere intregi cu operatille de adiugare a unui element, respec- tiv de scoatere a elementului din varful stivel. Dac presupunem cé stiva poate memora maxim 100 de elemente, ambele operatii pot provoca except Pentru a personaliza aceste exceptil vom crea o clash specifick denumitit ExceptieStiva: 1g 3.3; Exceptii proprii Glave ExceptieStiva extends Exception { public ExceptieStiva (String mesaj) { super(mesaj); + + class Stiva { int elemente[] = new int[100]; int n=0; //numarul de elemente din stiva public void adauga(int x) throws ExceptieStiva { if (n==100) throw nex ExceptieStiva("Stiva este plina!”); olemente[a++] + public int scoate() throws ExceptieStiva { if (n==0) throw hex ExceptieStiva("Stiva este goala!"); return elenente[n--]; + Seeventa cheie este extends Exception care specified faptul cd noua clasi ExceptieStiva este subclasi a clasei Exception si deci implementeazi obiecte ce reprezinta exceptii 94 CAPITOLUL 3. EXCEPTIL In general, codul aditugat claselor pentru exceptil propril este nesemnificativ: unul sau doi constructori care afigeaza un mesaj de eroare la iesinea standard, Procesul de creare a unei noi exceptii poate fi dus mai departe prin adaugarea tunor noi metode clasei ce descrie acca exceptic, ins’ aceasta dezvoltare mu isi are rostul in majoritaten cazurilor. Exceptiile proprii sunt descrise uzual de clase foarte simple, chiar far’ nici un cod in ele, oum ar fi class ExceptieSimpla extends Exception { } Aceastit clas se bazeazi pe constructorul implicit creat de compilator inst nu are constructorul ExceptieSimpla(String s) Capitolul 4 4.1 Introducere 4.1.1 Ce sunt fluxurile? Majoritatea aplicatiilor necesit citirer unor informatii care se giisese pe © surs extern’ sau trimiterea unor informatii citre o destinatie extern’. Informatia se poate gsi oriunde: intr-un fisier pe dise, in retea, in memorie sau in alt program si poate fide orice tip: date primitive, obiecte, imagini, sunete, ete. Pentru a aduce informatii dintr-un mediu extern, un progam Java trebuie si deschida un canal de comunicatie (fluz) de la sursa informatiilor (figicr, memoric, socket, etc) gi s& citeasci secvential informatiile respective. Similar, un program poate trimite informatii citre o destinatie extern deschizfind un canal de comunicatie (flux) citre acea destinatie si scriind secvential informatiile respective. Indiferent de tipul informatiilor, citivea/scrierea de pe/etitre un mediu extern respect urmitorul algoritm: deschide canal commicatie while (mai sunt informatii) { citeste/scrie informatie; + inchide canal comunicatie; Pentru a generaliza, atat sursa extern’ a unor date cat si destinatia lor sunt vazute ca fiind nigte procese care produc, respectiv consuma informatii 95 96 CAPITOLUL 4, INTRARI SI IESIRI Un flureste un canal de comunicatie unidirectional intre dou’ procese. Un proces care desorie o sursit externi de date se numeste proces produciiton, Un proces care descrie o destinatie externa pentru date se numeste proces consumator. Un flux care citeste date se numeste flue de intrare. Un flux care serie date se numeste flur de desire. Observatii: Fluxurile sunt canale de comunicatie seriale pe 8 sau 16 biti Fluxurile sunt unidirectionale, de la produeitor la consumator. Fiecare flux are un singur proces producitor si un singur proces consumater. Intre dowd procese pot exista oricdte fluxuri, orice proces putand fi atat pro- ducator cat si consumator in acelasi timp, dar pe fuxuri diferite. Consumatorul si produeatornl na comunick direct printr-o interfat de flux ci prin intermedia! codului Java de tratare a fluxurilor Clasele ai intefetele standard pentru lucrul on fluxuri se gisese in pachetul java.io. Deci, orice program care necesiti operatii de intrare sau iesire tre- buie si contin instructiunea de import a pachetului java.ict import java.io.*; 4.1.2. Clasificarea fluxurilor Exist trei tipuri de clasificare a fluxurilor: © Dupi directia canalului de comunicatie deschis fluxurile se impart in — fluxuri de intrare (pentru citirea datelor) — fluxuri de iegire (pentru serierea datelor) © Dupa tipul de date pe care operenzs — fluxuti de octeti (comunicarea seriala se realizeaza pe & biti) — fluxuri de caractere (comunicarea serial se realizeaza pe 16 biti) 41. INTRODUCERE oT ¢ Dupi acttunea lor: — fluxuri primare de citire/scriere a datelor (se ocupli efectiv on citirea/scrierea datelor) — fluxnri pentru procesarea datelor 4.1.3 Ierarhia claselor pentru lucrul cu fluxuri Clasele ridiicin’ pentru ierarbiile ce reprezintit flaxuri de caractere sunt @ Reader: pentru ftaxuri de intrare si ¢ Writer: pentru fluxuri de iesire Acesten sunt superclase abstracte pentru toate clasele ce implementenzi fluxuri specializate pentru citirea/scrierea datelor pe 16 biti si vor contine metodele comune tuturor. Ca o regulii generali, toate clasele din aceste ierarhii vor avea terminatia Readersau Writer in functie de tipul lor, cum ar fi in exemplele: FileReader, BufferedReader, FileWriter, BufferedWriter, etc. De asemenea, se ob- servi ca o alti regul generala, faptul ci unui flux de intrare XReader ii corespunde uzual un flux de iesire NWriter, insk acest lucru nu este obliga- toriu. Clasele radacini pentru ierarhia fluxurilor de octeti sunt: © InputStream: pentru fluxuri de intrare si ¢ OutputStream. pentru fluxuri de iesire Acestea sunt superclase abstracte pentru clase ce implementeazi fluxuri specializate pentru citiren/Scrierea datelor pe § biti. Ca si in cazul flux- urilor pe caractere denumirile claselor vor avea terminatia superclasei lor: FileInputStream, Buf feredInputStrean, FileOutputstrean, BuffereddutputStrean ete., fiecitul flux de intrare XInputStream core- spunzindu-i uzual un flux de iesire XOutputStream, fir ca acest lueru six fie obligatoriu 98 CAPITOLUL 4, INTRARI SI IESIRI Pana la un punct, exist’ un paralelism intre ierarhia claselor pentru flux: uri de caractere si cea pentru fluxurile pe octeti. Pentru majoritatea pro- gramelor este recomandat ca scrierea si citirea datelor si se fact prin inter- mediul fluxurilor de caractere, deoarece acestea permit manipularea carac- terelor Unicode in timp ce fluxurile de octeti permit doar lucrul pe 8 biti - caractere ASCII 41.4 M Superclasele abstracte Reader gi InputStream definese metode similare pen- tru citirea datelor. tode comune fluxurilor Reader InputStream int read() int_readQ int read(char buf[]) | int read(byte bufl]) De asemenea, ambele clase pun la dispozitie metode pentru marcarea unei locafii intr-un flux, saltul peste un numir de pozitii, resetarea pozitiel curente, etc. Acestea sunt ins mai rar folosite si mu vor fi detaliate. Superclasele abstracte Writersi OutpatStreamsunt de asemenea paralele definind metode similare pentru scrierea datelor Reader TaputStream void write(int c) woid write(int c) void write(char buf[]) | void write(byte bufL]) void write(String str) [- Inchiderea oricirui flux se realizeaz prin metoda close. In cazul in care aceasta nu este apelati explicit, fluxul va fi automat inchis de citre colectorul de gunosie atunci cénd nu va mai exista nici o referinta le el, inst acest Tuer trebuie evitat deoarece, la lucrul cu fluxrui cu zon tampon de memorie datele din memorie vor fi pierdute la inchideren fluxului de catre ge. Metodele referitoare la fluxuri pot genera exeeptii de tipul IOException sau derivate din aceasti class, tratarea lor fiind obligatorie. 4.2. FOLOSIREA FLUXURILOR, 99 4,2 Folosirea fluxurilor Asa cum am vizut, fluxurile pot fi impiirtite in functie de activitatea lor in fluxuri care se ccupi efectiv cu citirea/scrierea datelor si fluxuri pentru procesarea datelor (de filtrare). In continuare, vom vedea care sunt cele mai importante clase din cele doua categorii gi la ce folosese acestea, precum si modalititile de creare si utilizare a fluxurilor 4.2.1 Fluxuri primitive Fluxurile primitive sunt responsabile cu citirea/scrierea efectiva a datelor, punand le dispozitie implementiri ale metodelor de baz read, respectiv write, definite in superclase. In functie de tipul sursei datelor, ele pot fi ‘impirtite astfel: @ Fisier FileReader, FileWriter FileInputStream, FileOutputStrean Numite si fiueuri figier, acestea sunt folosite pentru citirea datelor dintr-un fisier, respectiy scrierea datelor intr-un fisier si vor fi anallizate Intr-o sectiune separat (vezi ”Fluxuri pentru luccul cu fisiere”) * Memorie CharArrayReader, CharArrayliriter ByteArraylnputStream, ByteArrayOutputStream Aceste fluxuri folosese pentru scrierea/citivea informatiilor in/din mem- orie si sunt create pe un vector existent deja. Cu alte cuvinte, permit tratarea vectorilor ca sursé/destinatie pentru crearea unor fluxuri de intrare/iegire, StringReader, StringWriter Permit tratarea sirurilor de caractere aflate in memorie ca sursi/destinatie pentru crearea de fluxuri * Pipe PipedReader, Pipediiriter PipedInputStream, PipedutputStream Implementeazi componentele de intrare/iesire ale unei conducte de 100 CAPITOLUL 4, INTRARI SI IESIRI date (pipe). Pipe-urile sunt folosite pentru a canaliza iesirea unui pro- gram sau fir de executie cittre intrarea altui program sau fir de executie 4.2.2 Fluxuri de procesare Fluxurile de procesare (sau de filtrare) sunt responsabile cu preluarea datelor de la un flux primitiv si procesaren acestora pentru a Ie oferi intr-o alti form, mai util dintr-un anumit punct de vedere. De exemplu, BufferedReader poate prelua date de la un flux FileReader si si ofere informatia dintr-un fisier linie cu linie, Find primitiv, FileReader nu putea citi decat caracter cu caracter. Un flux de procesare nu poate fi folosit decat impreun’ eu un flux primitiv. Clasele ce descriu aceste fluxuri pot fi impertite in functie de tipul de procesare pe care il efectueaza astfel: * "Bufferizare” BufferedReader, Bufferediiriter BufferedInputStream, BufferedOutputStream Sunt folosite pentru a introduce un buffer in procesul de citire/scriere a informatiilor, reducind astfel numiirul de accesi la dispozitival ce reprezintit sursa/destinatia original a datelor. Sunt mult mai eficiente decat fluxurile fir’ buffer si din acest: motiv se recomanda folosirea lor ori de cate ori este posibil (vezi ”Citirea si scricrea cu zona tampon”). ¢ Filtrare FilterReader, Filteririter FilterInputStream, FilterOutputStream Sunt clase abstracte ce definese o interfat comuni pentru fluxuri care filtreazit automat datele citite sau scrise (vezi ” Fluxuri pentru filtrare”) * Conversie octeti-caractere InputStreanReader, OutputStreanliriter Formeazi o punte de legaturit intre fuxurile de caractere gi fluxurile de octeti. Un flux InputStreamReader citeste octeti dintr-un flux InputStream si ii converteste la caractere, folosind codificarea stan- dard a caracterelor sau o codificare specifieati de program, Similar, un flax GutputStreaniiriter converteste caractere in octeti si trimite rezutatul citre un flux de tipnl GutputStream. 4.2. FOLOSIREA FLUXURILOR, 101 ¢ Concatenare SequenceInputStream Coneateneazi mai multe fluxuri de intrare intr-unul singur (vezi ”Con- catenarea fisicrelor”). # Serializare ObjectInputStream, ObjectOutputStream Sunt folosite pentru serializarea obiectelor (vezi "Serializarea obiectelor”) © Conversie tipuri de date DatalnputStream, DataQutputStrean Folosite la scrierea/citirea datelor de tip primitiy intr-un format binar, independent de masina pe care se Increazi (vezi *Folosirea clasclor DatalnputStream si DataOutputStream”). ¢ Numérare LineNumberReader Linelunber InputStream Ofer si posibilitatea de numirare automat a liniilor citite de la un finx de intrare ¢ Citire in avans PushbackReader PushbackInputStream Sunt fluxuri de intrare care au un buffer de 1-caracter(octet) in care este citit in avans si caracterul (octetul) care urmeazit celui curent citit. © Afisare PrintWriter PrintStream Ofer metode convenabile pentru afisarea informatiilor 4.2.3. Crearea unui flux Orice flux este un obiect al clasei ce implementeazi fluxul respectiv. Crearea unui flux se realizeazit agader similar cu crearea obiectelor, prin instructiunen new gi invocarea unui constructor corespunzator al clasei respective: Exemple: 102 CAPITOLUL 4, INTRARI SI IESIRI //crearea unui flux de intrare pe caractere FileReader in = new FileReader("fisier.txt"); //crearea unui flux de iesire pe caractere FileWriter out = new FileWiriter("fisier.txt") ; //crearea unui flux de intrare pe octeti FileInputStream in - new FileInputStream("fisier.dat") ; //orearea unui flux de iesire pe octeti FileOutputStrem out - new FileGutputStream("fisier.dat") ; Agadar, crearea unui flux primitiv de date cate citeste /scrie informatii de la un dispozitiv extern are formatul general FluxPrimitiv numeFlux = new FluxPrimitiv(dispozitivExtern); Pluxurile de procesare nu pot exista de sine stittitoare ci se suprapun pe un flux primitiv de citire/soriere a datelor. Din acest motiv, construetorii claselor pentru fluxurile de procesare nn primese ca argument un dispozitiv extern de memorare a datelor ci o referinta la un flux primitiv responsabil cu citirea/scrierea efectiva a datelor Exeuple: //crearea unui flux de intrare printr-un buffer BufferedReader in = new BufferedReader( new FileReader("fisier.txt")) ; //echivalent cu FileReader fr = new FileReader("fisier. txt"); BufferedReader in = new BufferedReader (Er) ; //crearea unui flux de iesire printr-un buffer BufferedWriter out = new Bufferediriter( new FileWriter("fisier.txt"))); //echivalent cu FileWriter fo = new FileWriter("fisier.txt"); BufferedWriter out = new BufferedWriter (fo) ; Agadar, crearea unui flux pentru procesarea datelor are formatul general 4.2. FOLOSIREA FLUXURILOR, 103 FluxProcesare numeFlux = new FluxProcesare(fluxPrimitiv); In general, fluxurile pot fi compuse in succesiuni orieat de lungi: DatalnputStrean in = new DatalnputStrean( new BufferedInputStream( new FileInputStream("fisier.dat"))) ; 4.2.4 Fluxuri pentru lucrul cu figiere Fluxurile pentru Iucrul cw figiere sunt cele mai usor de inteles, intrucat operatia lor de baz este citirea, respectiv scrierea unui caracter sau octet dintr-un san intr-un figier specificat wzual prin numele su complet sau relativ la directorul curent. Dupi cum am vazut deja, clasele care implementeazi aceste fluxuri sunt urmitoarele FileReader, FileWriter ~ caractere FileInputStream, FileOutputStream - octeti Constructorii acestor clase acceptii ca argument un obiect care si specifice lun anume figier. Acesta poate fi un sir de caractere, on obiect de tip File sau un obiect de tip FileDesciptor (vezi Clasa File”) Constructorii clasei FileReader sunt: public FileReader (String fileName) ‘throws FileWotFoundException public FileReader(File file) throws FileNotFoundException public FileReader(FileDescriptor fd) Constructorii clasei Filelriter: public FileWriter(String fileName) throws IOException public FileWriter(File file) throws IOException public FileWriter(FileDescriptor fd) public FileWriter(String fileName, boolean append) throws IOException 104 CAPITOLUL 4, INTRARI SI IESIRI Cei mai uzuali constructori sunt cei care primese ca argument numele fisierului. Acestia pot provoca exceptii de tipul FileNotFoundException in cazul in care fisierul cu numele specificat nu exist. Din acest motiv orice creare a unui flux de acest tip trebuie ficuta intr-un bloc try-catch sau metoda in care sunt create fluxurile respective trebuie si arunce exceptiile de tipul FileNotFoundException sau de tipul superclasci IOException. $4 considerim ca exemplu un program care copie continutul unui fisier cu numele "in.txt” intr-un alt fisier cu numele "out.txt”. Ambele figiere sunt considerate in directorul curent. Listing 4.1: Copierea unui fisier import java.io.*; public class Copiere ¢ public static void main(String] args) ¢ try { FileReader in = new FileReader("in.tzt"); FileWriter out = new Fileriter("out.txt"); int cj while ((c = in.read()) out write (e); -1) in. close(); out .close(); } catch (IOException ¢) { System.err.printin("Eroare la operatiile cu fisiere!"); e.printStackTrace (); + 3 3 In cazul in care vom lansa aplicatia iar in directorul curent nu exist’ un fisier cu numele ”in.txt”, va fi generati o exceptie de tipul FileNotFoundException Aceasta va fi prinsk de program deoarece, IOException este superclasa pentru FileNotFoundException, Daci existit fisierul "in.txt”, aplicatia va crea un nou fisier "out.txt” in care va fi copiat continutul primului. Dack exist deja figierul ”out.txt el va fi re- 4.2. FOLOSIREA FLUXURILOR, 105 setis, Dac doream si facem operatia de adiugare(append) si nu de rescriere pentru fisierul “out.txt” foloseam’ FilelWiriter out = new FileWiriter("out.txt", true); 4.2.5 Citirea si scrierea cu buffer Clasele pentru citirea/scrierea cu zona tampon sunt: BufferedReader, BufferedWiriter ~ caractere BufferedInputStream, BufferedutputStream - octeti Sunt folosite pentru a introduce un buffer (zon de memorie) in proce- sul de citire/scricre a informatiilor, reducénd astfel numarul de accestiri ale dispozitivului ce reprezintii sursa/destinatia atelor. Din acest motiv, sunt mult mai eficiente decat fluxurile fir buffer gi din acest motiy se recomandit folosirea lor ori de cate ori este posibil Clasa BufferedReader citeste in avans date gi le memoreszi intt-o zon tampon, Atunci cand se executi o operatie de citire, caracterul va fi pre- Juat din buffer. In cazul in care butfer-ul este gol, citirea se face direct din flux si, odatil cu citirea caracterului, vor fi memorati in buffer si caracterele care ji urmeazit, Evident, Buffered InputStream functioneazi dupi acelasi principiu, singura diferent fiind faptul cX sunt cititi octeti. Similar lucreaza si clasele Bufferediiriter si Buffered0utputStream La operatiile de scriere datele scrise nu vor ajunge direct I destinatie, ci vor fi memorate jntr-un buffer de o anumit dimensiune. Atunci cind bufferul este plin, continutul acestuia va fi transferat automat la destinatie. Fluxurile de citireyscriere cu buffer sunt fluxuri de procesare si sunt folosite prin suprapunere cu alte fluxuri, dintre care obligatoriu unul este primitiy. BufferedOutputStream out = new BufferedQutputStream( new FileQutputStream("out.dat"), 1024) //1024 este dimensiunea bufferului Constructorii cei mai folositi ai acestor clase sunt. urmitorii: BufferedReader (Reader in) BufferedReader (Reader in, int dim_buffer) Bufferediriter (Writer out) 106 CAPITOLUL 4, INTRARI SI IESIRI Buffered¥riter(Writer out, int dim buffer) BufferedInputStream(InputStream in) BufferedInputStream(InputStream in, int dim_buffer) Buffered0utputStream (OutputStream out) Buffered0utputStream (OutputStream out, int dim_buffer) In cazul constructorilor in care dimensiunea buffer-ului nu este specifiesti, aceasta primeste valoarea implicitii de 512 octeti (caractere) Metodele acestor clase sunt cele uzuale de tipul read gi write. Pe langa acestea, clasele pentru scriere prin buffer mai au i metoda flush care goleste explicit zona tampon, chiar dact aceasta nu este plind. BufferedWriter out = new Bufferedifriter( new FileWiriter("out.dat"), 1024) //an creat un flux cu buffer de 1024 octeti for(int i=0; i<1000; i++) out .write (i) ; //oufferul nu este plin, in fisier nu s-a scris nimic out. flush() ; //oufferul este golit, datele se scriu in fisier Metoda readLine Este specificd fluxurilor de citire eu buffer si permite citirea linie cw linie a datelor de intrare. O linie reprezintii o succesiune de caractere terminaté cu simbolul pentru sfargit de linie, dependent de platforma de lucru. Acesta este reprezentat in Java prin seeventa escape "\v’; BufferedReader br = new BufferedReader(new FileReader("in")) String linie; vhile ((linie = br.readLine()) null) { //proceseaza linie + br.close(); 3 4.2. FOLOSIREA FLUXURILOR, 107 4.2.6 Concatenarea fluxurilor Clasa SequenceInputStream permite unei aplicatii si combine serial mai multe fluxuri de intrare astfel incét acestea si apard ca un singur flux de intrare, Citirea datelor dintr-un astfel de flux se face astfel: se citeste din primul flux de intrare specificat pana cand se ajunge la sfarsitul acestuia, dupa care primul flux de intrare este inchis si se deschide automat urmatorul flux de intrare din care se vor citi in continuare datele, dupa care procesul se repeti pana la terminarea tuturor fluxurilor de intrare. Constructorii acestei clase sunt: SequenceInputStream(Enumeration e) SequenceInputStream(InputStream s1, InputStream #2) Primul construieste un flux secvential dintr-o multime de fluxuri de in- trare. Fiecare obiect in enumerarea primitii ca parametru trebuie si fie de tipul InputStream. Cel de-al doilea construieste un flux de intrare care combina doar doua fluxuri Lsi 2, primul ux citit fiind 1 Exemplul cel mai elocvent de folosirea a acestei clase este concatenarea a dowi sau mai multor fisiere: Listing 4.2: Concatenarea a dou figiere 7* Concatenarea a dowa fistere ale caror nume sunt primite de la linea de comanda Resultatul concatenarti este aftsat pe ecran “/ import java.io.) public class Concatenare { public static void main(String args[]) ¢ if (args length <= 1) ¢ System. out .printin("Argumente insuficiente!"); System. exit (-1); + try { FileInputStream f1 = new FileInputStream(args [0]); FilelnputStream £2 = new FileInputStream(arge [1]); SequencelnputStrean s = nex SequencelnputStream (fi, £2) int ¢; while ((e = s.read()) t= -1) System. out. print ((char)¢) ; 108 CAPITOLUL 4, INTRARI SI IESIRI s.close(); //f1 31 f2 sunt inchise automat } catch (0Exception e) ( ¢.printStackTrace() ; > > x Pentru concatenarea mai multor fisiere exist dou variante: # folosirea unei enumeriti - primul constructor (vezi ”Colectii”) © concatenarea pe rind a acestora folosind al 2-lea constructor; con- catenarea a 3 figiere va construi un flux de intrare astfel: FileInputStream f1 = new FileInputStream(args(0]) ; FileInputStream £2 = new FileInputStream(args[1]); FileInputStream £3 = new FileInputStream(args[2]); SequenceInputStream s = new SequenceInputStream( f1, new SequencelnputStream(f2, £3); 4.2.7 Fluxuri pentru filtrarea datelor Un flux de filtrare se atageazi altui flux pentru a filtra datele care sunt citite/scrise de citre acel flux. Clasele pentru filtrarea datelor superclasele abstracte: ¢ FilterInputStream - pentru filtrarea fluxurilor de intrare si ¢ FilterOutputStream- pentru filtrarea fluxurilor de iesine Cele mai importante fuxruri pentru filtrarea datelor sunt implementate de clasele: DatalnputStream, DataQutputStream BufferedInputStream, Buffered0utputStream Linelumber InputStream PushbackInputStrean PrintStream 4.2. FOLOSIREA FLUXURILOR, 109 Observati ci toate aceste clase descriu fluxuri de octeti. Filtrarea datelor nu trebuie viizutd ca o metod’ de a elimina anumiti octeti dintr-un flux ci de a transforma acesti octeti in date care sii poata fi interpretate sub alt& forma, Aga cum am viizut la citirea/scrierea cu zonit tampon, clasele de filtrare Buf feredInputStreamsi BufferedOutputStream colecteaz datele unui flux intr-un buffer, urménd ca citirea/scrierea si se fac’ prin intermedin acelui buffer. Agadar, fluxurile de filtrare nu elimina date citite sau scrise de un anumit flux, ci introdue o noua modalitate de manipulare a lor, ele mai fiind numite si fiururi de procesare, Din acest motiv, fluxurile de filtrare vor contine anumite metode specializate pentru citirea/scricrea datelor, altele decat cele comune tuturor fluxurilor. De exemplu, clasa BufferedInputStream pune la dispozitie metoda readLine pentru citirea une! linii din fluxul de intrare. Polosirea fluxurilor de filtrare se face prin atagarea lor de un flux care se ocupa efectiv de citirea/scrierea datelor: FluxFiltrare numeFlux = new FluxFiltrare(referintaAltFlux) ; 4.2.8 Clasele DataInputStream gi DataQutputStream Aceste clase oferli metode prin care un flux nu mai este vézut ca o insiruire de octeti, ci de date primitive. Prin urmare, vor furniza metode pentru citirea si scrierea datelor la nivel de tip primitiv si mu la nivel de octet. Clasele care ofer un astfel de suport implementeaza interfetele Datalnput, respectivDataOutput. Acestea definesc metodele pe care trebuie sé le punt In dispozitie in vederea citireii/scrierii datelor de tip primitiv. Cele mai folosite metode, altele decat cele comune tuturor fluxurilor, sunt date in tabelul de mai jos 110 CAPITOLUL 4, INTRARI SI IESIRI DatalnputSiream [ DataOutputStream readBoolean writeBoolean readByte writeByte readChar writechar readDouble writeDouble readFloat writeFloat readint writeInt readLong writeLong readShort writeShort readUTF writel TF Aceste metode au denumirile generice deread XXX gi writeXXX, specifi- cate de interfetele Datalnput si DataDutput si pot provoca exceptii de tipul IOException. Denumirile lor sunt sugestive peutru tipul de date pe care il prelucreazi. mai putin readUTF si writeU'TF care se ocupi cu obiecte de tip String, fiind singurul tip refering. permis de aceste clase Scrierea datelor folosind fluxuri de acest: tip se face in format, binar, ceea ce inseammii ci un fisier in care au fost scrise informatii folosind metode writeXNN nu va putea fi citit decat prin metode readXXX, ‘Transformarea unei valor in format binar se numeste serializare Clasele DataInputStream si DatautputStream permit serializarea tipurilor prim- itive si a sirurilor de caractere. Serializarea celorlalte tipuri referinti va fi facut’ prin intermediul altor clase, cum ar fi Object InputStream si ObjectOutputStream (vezi *Serializaren obicctelor”) 4.3 Intrari gi iesiri formatate Incepand cn versiunea 1.5, limbajul Java pune la dispozitii modelitati sim- plificate pentru afigarea formatati a unor informatii, respectiv pentru citirea de date formatate de la tastaturd. 43.1 Intrari formatate Clase java.util. Seamner oferi o solutie simpla pentru formatarea nor informatil citite de pe un flux de intrare fie pe octeti, fie pe caractere, sau chiar dintr-un obiect de tip File. Pentru a citi de la tastaturd vom specifica ca argument al constructorului fluxul System. in: 4.4, FLUXURI STANDARD DE INTRARE SI IESIRE iil Scanner s = Scanner. create (System. in) ; String nume = s.next(); int varsta = s.nextInt(); double salariu * s.nextDouble(); s.close(); 4.3.2 lesiri formatate Clasele PrintStream si PrintWriter pun la dispozitiile, pe langa metodele print, printin care oferean posibilitatea de a afiga un sir de caractere, si metodele format, printf (echivalente) ce permit afigarea formatati a unor variabil. System.out.printf("%s %8.2f %2d %n", nume, salariu, varsta); Formatarea sirurilor de caractere se bazeaz pe clasa java.util. Formatter. 4.4 Fluxuri standard de intrare si iesire Mergand pe linia introdusi de sistemul de operare UNIX, orice program Java are © o intrare standard © 0 iegire standard © 0 iesite standard pentru erori In general, intrarea standard este tastatura iar iegirea standard este ecranul. Intrarea gi iegirea standard sunt reprezentate de obiecte pre-create ce descriu fluxuri de date care comunica cu dispozitivele standard ale sistemului. Aceste obiecte sunt definite publice in clasa System si sunt: ¢ System. in - fluxul standar de intrare, de tip InputStream ¢ System.out - fluxul standar de iesire, de tip PrintStream ¢ System.err - fluxul standar pentru erori, de tip PrintStream 112 CAPITOLUL 4, INTRARI SI IESIRI 44,1 Afisarea informatiilor pe ecran Am vizut deja numeroase exemple de utilizare a fluxului standard de iesire, el fiind folosit Ia afigarea oricaror rezultate pe ecran (in modul consola) System.out.print (argument) ; System.out.print1n (argument) ; System.out.printf (format, argumente...); System.out.format (format, argumente...); Pluxul standard pentru afigarea erorilor se foloseste similar si apare uzual in seoventele de tratare a exceptillor. Implicit, este acelagi cu fluxul standard de iesire, catch(Exception ¢) { System.err.println("Exceptie:" + e); + Fluxurile de iesire pot fi folosite agadar fri probleme deoarece tipul lor este PrintStream, clas concretit pentru scrierea datelor. In schimb, fluxul standard de intrare System. out este de tip InputStream, care este o clas abstracti, deci pentru a-l putea utiliza eficient va trebui sa-l folosim impreuna cu un flux de procesare(filtrare) care sit permiti citires facil a datelor. 4.4.2 Citirea datelor de la tastatura Uzual, vom dori si folosim metoda readLine pentru citirea datelor de la tastatura si din acest motiv vom folesi intrarea standard impreuni cu o clas de procesare care oferit aceastit metod’. Exemplul tipic este: BufferedReader stdin = new BufferedReader( new InputStreanReader (System. in)); System.out.print("Introduceti o linie:"); String linie = stdin.readLine() System.out.printIn(linie) ; In exemplul urmiitor este prezentat un program care afigeaza linille intro- duse de la tastatura pan’ in momentul in care se introduce linia "exit” sau 6 linie vida si mentioneazidaci sirul respectiv reprezint& un numér sau nu. 4.4, FLUXURI STANDARD DE INTRARE SI IESIRE 113 Listing 4.3: Citirea datelor de la tastaturé, /* Citeste sirurt de la tastatura si verifica daca represinta nunere sau nu ” import java.io.*; public class Estellumar { public static void main(String(] args) ( BufferedReader stdin = new BufferedReader ( new InputStreamReader (System. in)); try { while(true) { String s = stdin-readLine(); if (s.equals("exit") || s.length( break; System. out . print (s); try { Double. parseDouble(s); System. out. printin(": DA"); } catch(NumberFormatException e) { System. out.printin(": MU"); + + + catch(I0Exception e) { System.err.printIn("Eroare la intrarea standard!"); ©.printStackTrace(); } + » Incepind ou versiunea 1.5, varianta cea mai comodi de citire a datelor de la tastaturi este folosiren clasel java.util. Scanner. 4.4.3. Redirectarea fluxurilor standard Redirectarea fluxurilor standard presupune stabilirea unei alte surse decat tastatura pentru citirea datelor, respectiv alte destinatii decat ccranul pentru cole dows fiuxuri de iegire. In clasa Systemexist urmatoarele metode statice care realizeaz acest lucru setIn(InputStream) - redirectare intrare setOut(PrintStream) - redirectare iesire setErr(PrintStream) - redirectare erori 114 CAPITOLUL 4, INTRARI SI IESIRI Redirectarea iesirii este utili in special atunci eénd sunt afigate foarte multe date pe ecran. Putem redirecta afisarea ctre un fisier pe care st-1 citim dupa executia programului, Secventa clasici de redirectare a iesirii este ciitre un fisier este: PrintStream fis - new PrintStream( new FileOutputStream("rezultate.txt"))) ; System.setOut (fis) ; Redirectarea etorilor intr-un fisier poate fi de asemenea util si se face intr-o maniera similar’ PrintStream fis = new PrintStream( new FileQutputStream("erori.txt"))); System.setErr(fis) ; Redirectarea intratii poate fi folositoare pentru un program in mod con- soli care primeste mai multe valori de intrare. Pentru a nu le serie de la tastaturi de fiecare dat in timpul testarii programului, ele pot fi puse intr- un fisier, redivectand intrarea standard catre acel figier. In momentul cand testarea programului a luat sfarsit redirectarea poate fieliminat, datele fiind cerute din nou de la tastaturd. Listing 4.4: Exemplu de folosire a redivectivil: import java.io # class Redirectare { public static void main(String[] args) { ery { BufferedInputStrean in = nev BufforedInputStrean( new FileInputStrean(*intrare.txt")) ; PrintStream out = new PrintStream( new FileQutputStream("rezultate.txt")); PrintStrean orr = new PrintStrean( new FileQutputStrean("erori. txt")); System. cotin (ia); System. cetOut (out); System. setErr (err); BufferedReader br = new Bufferedneader ( new InputStreamReader (System. in)); 4.4, FLUXURI STANDARD DE INTRARE SI IESIRE 115 String sj while((s = br.readLine()) != null) { /* Lintile vor fa citate din fisterul intrare. tet si vor fi serise in fisterul rezultate. tat 7A Systom. out. printin(s); + H/Aruncam fortat o exceptie throw new I0Exception("Test”) ; } cateh(10Exception ¢) { /* Daca apar ezceptis, ele vor fi scrise in fistervl erord.tat / System.err.println("Eroare intrare/iesire!"); e.printStackTrace(); 44.4 Analiza lexicala pe fluxuri (clasa StreamTokenizer) ClasaStreanTokenizer proceseazii un flux de intrare de orice tip stil imparte in “atomi lexicali”. Rezultatul va consta in faptul ca in loc sa se citeasci octeti sau caractere, se vor citi, pe rand, atomii lexicali ai fluxului respectiv. Printr-un atom lexicalse injelege in general © un identificator (un sir care nu este intre ghilimele) un numar ¢ un sir de caractere @ un comentariu # un separator Atomii lexicali sunt despiirtiti intre ei de separatori. Implicit, acesti separa- tori sunt cei obisnuti: spatiu, tab, virgul4, punct si virgula, ete., inst pot fi schimbati prin diverse metode ale clasei Constructorii elasei sunt 116 CAPITOLUL 4, INTRARI SI IESIRI public StreanTokenizer(Reader r) public StreanTokenizer (InputStream is) Identificarea tipului si valorii unui atom lexical se face prin intermedi! variabilelor ¢ TT-_EOF - atom ce marcheazi sfaarsitul fluxului ¢ TT-EOL- atom ce marcheazi sfarsitul unei lini ¢ TT-NUMBER- atom de tip numir ¢ TT_WORD- atom de tip cuvant © ttype tipul ultimului atom citit din flux ¢ nval valoarea unui atom numeric ¢ sval- valoarea unui atom de tip euvant Cities atomilor din flux se face cu metodanext'Token(), care retiurnezit tipul atomului lexical citit si scrie in variabilele nval saul sval valoarea core- spunzatosire atomului Exemplul tipic de folosire a unui analizor lexical este citirea unei seevente de numere gi siruri aflate intr-un figier sau primite de la tastatur’: Listing 4.5: Citirea unor atomi lexicali dintr-un fisier 7* Citires unei secvente de numere 1 sirura dintr-un fister speceficat st afisarea tepului st valorid lor / import java.io. public class CitireAtomi { public static void main(String args[]) throws I0Exception( BufferedReader br = new BufferedReader (new FileReader (" fisier.txt")); StreamTokenizer et = new StreanTokenizer (br); int tip = st.nextToken(); //8e citeste primul atom lexical 45. 3A RANDOMACCESFILE (FISIERE CU ACCES DIRECT) iz while (tip != StreanTokenizer.TT_B0F) { switch (tip) { case StreanTokenizer .TT_WORD System.out.printin("Cuvant: " + st.sval); break; case StreanTokenizer .TT_NUMBER System.out.printla("Wumar: * + st.nval); tip = st.nextToken(); //Trecem la urmatorul atom Agadar, modul de utilizare tipic pentru un analizor lexical este intr-o bu- cla "while", im care se citese atomii unul cate unul cu metoda nextToken, pana se ajunge la sfarsital fluxului (TT-EOF). In cadrul buclei “while” se deter mind tipul atomul curent curent (intors de metodanextToken) si apoi se afla valoarea numerici sau sirul de caractere corespunziitor atomului respectiy. In cazul in care tipul atomilor nu ne intereseazii, este mai simplu si citi fluxul linie cu linie sis folosim clasaStringTokenizer, care realizeazi ‘impirtirea unui sir de caractere in atomi lexieali, sau metoda split a clasei String. 4.5 Clasa RandomAccesFile (figiere cu acces di- rect) Dup& cum am vizut, fluxurile sunt procese secventiale de intrare/iesire. ‘Acestea sunt adeovate pentru Iucrul cu medii secventisle de memorere a datelor, cum ar fi banda megneticS sau pentru transmiterea informatiilor prin retea, desi sunt foarte utile si pentru dispozitive in care informatia poate fi accesata direct. Clasa RandomAccesF ile are urmitoarele caracteristici * permite accesul neseevential (direct) la continutul unni fisier; «# este o clas de sine stititoare, subclasi directit a clasei Object; « se giiseste in pachetul java. io; 118 CAPITOLUL 4, INTRARI SI IESIRI * implementeaaa interfetele DataInput si DataQutput, cea ce inseamna ca sunt disponibile metode de tipul read XXX, writeXXX, intocmai ca la clasele DataInputStream si DataOutputStream, ‘¢ permite atat citirea cit gi scriere din/in fisiere cu acces direct; © permite specificarea modului de acces al unui fisier (read-only, read write). Constructorii acestei clase sunt RandomAccessFile(StringnumeFisier, StringmodAcces) throws IOException RandomAccessFile(StringnumeFisier, StringmodAcces) ‘throws IOException unde madAcces poate fi: “1” - fisierul este deschis numai pentru citire (read-only) “rw” - figierul este deschis pentru citire gi seriere (read-write) Exemple: RandomAccesFile f1 = new RandomAccessFile("fisier.txt", "r"); //deschide un fisier pentru citire RandomAccesFile £2 = new RandomAccessFile("fisier.txt", "rv"); //deschide un fisier pentru scriere si citire Clasa RandomAccesFilesuporti notiunea de potnter de figier: Avesta este un indicator ce specifick pozitia curenti in fisier. La deschiderea unui fisier pointerul are valoarea 0, indieand inceputul fisierului, Apeluri la metodele de citire/scritere deplascaz pointerul figicrului cu numarul de octeti cititi san scrisi ce metodele respective In plus fatlide metodele de tip read si write clasa pune la dispozitie gi metode pentru controlul pozitiei pointerului de figier. Acestea sunt: ¢ skipBytes- muti pointerul fisierului inainte ou un numir specifieat de octeti © seek - pozitioneaza pointerului fisierului inaintea unui octet specificat * gotFilePointer - returneazit pozitia pointerului de fisier. 4.6. CLASA FILE 1g 4.6 Clasa File Clasa File nu se refer doar Ia un fisier ci poate reprezenta fie un fisier anume, fie multimea figierelor dintr-un director Specificarea unui fisier/director se face prin specificarea cai absolute spre acel fisier sau a cil relative fat de directorul curent. Acestea trebule si re specte conventille de specificare a cilor gi numelor figierelor de pe platforma de luern, Utilitate clasei File const in furnizarea unei modalititi de a abstractiza dependentele cailor si numelor fisierelor fatiide magina gazdi, precum si punerea la dispozitie a unor metode pentru lucrul cu fisere si directoare In nivelul sistemului de operare Astfel, in aceasti clast von gilsi metode pentru testarea existentei, stergerea, redenumirea unui fisier sau director, crearea unui director, listarea fisierelor dintr-un director, ete. Trebuie mentionat si faptul ch majoritatea constructorilor fluxurilor care permit accesul la figiere accepts ca argument un obiect de tip File in locul unui sit ce reprezinté numele fisierului respectiv. File f = new File("fisier.txt") ; FileInputStream in = new FileInputStream(f) Ce] mai uzual constructor al clasei File este public File(String nuneFisier) Metodele mai importante ale clasei File au denumiri sugestive si vor fi prezentate prin intermediul exemplului urmitor care listeaza fisierele si sub- directoarele unui director specificat si, pentru fiecare din ele afigeazit diverse informatii: Listing 4.6: Listarea continutului unui director’ 7* Programul listeaza fisterele st subdirectoarele unui director Pentru fiecare din ele vor fi afisate diverse informatié Mumele directorulus este primit ca argument de la Linta de comanda, sau este directorul curent ” import java.io.#; 120 CAPITOLUL 4, INTRARI SI IESIRI import java.util.*; public class ListareDirector { private static void info(File £) { //Afiseaza informatit despre un fisier sau director String nume = £. getName (); if. isFile() System.out.printin("Fisier: " + nume); else if(isDirectory()) System.out.printin("Director: * + nume); System. out .printin( "Cale absoluta: * + £.getAbeolutePath() + "\n Poate citi: * + £.canRead() + "\n Poate serie: " + f.canliriteQ + "\n Parinte: * + £.getParent() + "\n Cale: " + £.getPath() + "\n Lungime: " + f.length( + "\n Data ultimei modificari: * + new Date(£.lastModified ())); System. out. println(" 3 public static void main(String[] args) ¢ String nune; if (arge.length == 0) nume = "."; //directorul curent else aune = args [0]; try £ File director = new File(nume); File[] continut = director. listFiles(); for(int 4 = 0; i < continut.length; i++) info (continut [i]; } catch(Exception e) { e.printStackTrace (); + + 3 Capitolul 5 Interfete 5.1 Introducere 5.1.1 Ce este o interfata ? Interfetele due conceptul de clas abstractié cu un pas inainte prin eliminaren oricéror implementiti de metode, pundnd in practicd unul din conceptele programérii orientate obiect si anume cel de separare a modelului unui obiect, (interfat) de implementarea sa. Asadar, o interfat poate fi privita ca un protocol de comunicare intre obiecte. interfat Java defineste un set de metode dar nu specific’ nici o imple- mentare pentru ele. O clas care implementeazi o interfatti trebuie obligato- riu si specifice implementiiri pentru toate metodele interletei, supunandu-se agadar unui anumit comportament. Definitie O interfatit este o colectie de metode fir implementare gi declaratii de constante. Interfetele permit, alituri de clase, definirea unor noi tipuri de date. 121 122 CAPITOLUL 5. INTERFETE 5.2 Folosirea interfetelor 5.2.1 Definirea unei interfete Definirea unel interfete se face prin intermediul cuvantului cheie interface: [public] interface NumeInterfata (extends SuperInterfatal, SuperInterfata2...] { /* Corpul interfetei: Declaratii de constane Declaratii de metode abstracte */ + interfatii poate avea un singur modificator si anumepublic. O interfata, public este accesibili tuturor claselor, indiferent de pachetul din care fac parte, implicit nivelul de acces fiind doar la nivelul pachetului din care face parte interfata. interfatat poate extinde oricate interfete. Acestea se numese superinterfete si sunt separate prin virguli. (vezi ”Mostenirea multiplé. prin intermediul interfetelor”) Corpul unei interfete poate contine: @ constante: acestea pot fi sau nu declarate cu modificatorii public, static si final care sunt impliciti, nici un alt modificator neputand apirea in declaratia unei variabile dintr-o interfati, Constantele unei interfete trebuie obligatoriu initislizate. interface Exemplu { int MAX = 100; // Echivalent cu: public static final int MAX = 100; int MAX; // Tncorect, lipseste initializarea private int x = 1; // Incorect, modificator nepermis 5.2, FOLOSIREA INTERFETELOR 123 metode fir implementare: acestea pot fi sau nu declarate cu mod- ificatorul public, care este implicit; nici un alt modificator nu poate apirea in declaratia unei metode a unei interfete. interface Exemplu { void metoda() ; // Echivalent cu: public void metoda(); protected void metoda2(); // Incorect, modificator nepermis ‘Atentie ¢ Variabilele unei interfete sunt implicit publice chiar dact nu sunt declarate cu modificatorul public. © Variabilele unei interfete sunt implicit constante chiar daci nu sunt declarate cu modificatorii static gi final. ¢ Metodele unei interfete sunt implicit publice chiar dac nu sunt declarate cu modifieatorul public. ¢ In variantele mai vechi de Java era permis si modificatorul abstract in declaratia interfetei si in declaratiile metodelor, inst acest lucru nu mai este valabil, deoarece atat interfata cat si metodele sale nu pot fi altfel decat abstracte 5.2.2 Implementarea unei interfete Implementarea uneia sau mai multor interfete de clitre o clasii se face prin intermedinl cuvantulut cheis implements: class NumeClasa implements NumeInterfata sau class NumeClasa implements Interfatai, Interfata2, ... 124 CAPITOLUL 5. INTERFETE O clasit poate implementa oricdte interfete sau poate si nu implementeze nici una, In cazul in care o clas implementeazit o anumiti interfati, atunci tre buie obligatoriu si specifice cod pentru toate metodele interfetei. Din acest motiv, odati creata si folosit la implementarea unor clase, o interfati nu mai trebuie modificata, in sensul ch adiugarea unor metode noi sau schim- barea signaturii metodelor existente vor duce la erori in compilarea claselor care o implementeazi. Evident, o clas poate avea si alte metode gi variabile membre in afaré de cele definite in interfata Atentie Modificarea unei interfete implici modificarea tuturor claselor care im- plementeazit acea interfats. interfatit nu este o clasii, dar orice referinti de tip interfata poate primi cca valoare o referinta la un obiect al unei clase ce implementeazi interfata respectiva. Din acest motiy, interfetele pot fi privite ca tipuri de date si vom spune adesea ct un obiect are tipul X, unde X este o interfati, dacit acesta este o instant a unei clase ce implementeazi interfata X. Implementarea unei interfete poate s& fie si o clas abstract® 5.2.3 Exemplu: implementarea unei stive Sé consideriim urmitorul exempla. Dorim si implementiim un nou tip de date mumit Stack, care sti modeleze notiunea de stiva de obiecte. Obiectele de tip stiva, indiferent de implementarea lor, vor trebui si contin metodele © push - adaugi un now element in stivit pop- elimina elementul din varful stivei pook - retumeazi varful stivei ¢ ompty - testeazi daci stiva este vidi toString- returneaz continutul stivei sub forma unui sit de caractere 5.2, FOLOSIREA INTERFETELOR 125 Din punctul de vedere al structurii interne, o stiva poate fi implementati folosind un vector sau o list inkintuitd, ambele solutil avand avantaje si dezavantaje. Prima solutie este mai simplu de inteles, in timp ce a doua & mai eficienta din punetul de vedere al folosirii memoriei. Deoarece nu dorim sa legam tipul de date Stackde o anumita implementare structurala, i] vom defini prin intermediul unei interfete. Vom vedea imediat avantajele acestei abordit Listing 5.1: Interfata ce descrie stiva public interface Stack ¢ void push (Object item) throws StackException; void pop() throws StackException; Object peck() throws StackException; boolean empty 0; String toString); Pentru a trata situatiile anormale care pot apirea atunci cdnd incereém sii punem un element in stiva gi nu este posibil din lips de memorie, sau ‘incerckim si accestim varful stivei gi aceasta este vidi, vorn defini o exceptie ptoprie StackException: Li 2: Tipul de exceptie generat de stivi ing public class StackException extends Exception { public StackException() { super(); } public StackException(String msg) { super (msg) ; + Dim in continuare prima implementare a stivei, folosind un vector Listing 5.3: Implementarea stivei folosind un vector // Inplementarea stiver folosind un vector de obsecte public clase StackImpli implements Stack { private Object items []; //Wectorul ce contine obtectele 126 CAPITOLUL 5. INTERFETE private int 2=0; //Mumarel curent de elemente din stiva public StackImpli(int max) { //Constructor items = new Object [max]; 3 public StackImpli() { this (100) ; } Public void push(Object item) throws StackException { if (m == items. length) throw new StackException("Stiva este plina!"); itene[nt+] © item; 3 Public void pop() throws StackException { if Compty 0) throw new StackException("Stiva este vida!"); itens[--n] = null; 3 public Object peek() throws StackException { if Compty 0) throw new StackException("Stiva este vida!"); return itens(n-1]; + public boolean empty () { return (n==0); + public String toString { String 9=""; for(int 15 i>=0; i--) 2 t= iteme[i].tostring() + * *; return §; + + Remarcati c&, desi in interfatii metodele nu sunt declarate explicit cu modificatorul public, ele sunt totusi publice si trebuie declarate ca atare in clasi. ‘Trebuie remarcat si faptul ci metoda toString este definiti’ deja in clasa Object, deci clasa noastri o are deja implementat’ si nu am fi obtinut nici 6 eroaré In compilare dack nu o implementam explicit. Ceea ce facem acum este de fapt supradefinirea ei 5.2, FOLOSIREA INTERFETELOR 127 alti observatie importantii se refer’ la faptul cf trebuie si declariim in cadrul interfetei si exceptiile aruncate de metode, ce trebuie obligatorin tratate. Sa vedem acum modalitatea de implementare a stivei folosind o listi inlaintuitéi Listing 5.4: Tmplementarea stivei folosind o list 7/ Tnplenentarea stiver folosind o lista inlantuita public class StackImpl2 implements Stack { class Node { //Clasa interna ce reprezinta un nod al Lister Object item; //informatea din nod Node link; //legatura la urmatorul nod Node (Object item, Node link) £ this.item = item; this.link = link; + + private Node top=null: //Referinta la varful strives public void push (Object item) ¢ Node node = new Node(item, top); top = node; + public void pop() throws StackException { if Cempty 0) throw new StackException("Stiva este vidal’); top = top. link; + public Object peek() throws StackException ¢ if Cempty 0) throw new StackException("Stiva este vidal"); return top. item; + public boolean empty () { return (top == null); + public String toStringQ { String s="*; Node node = top; while (node != null) { 128 CAPITOLUL 5. INTERFETE 5 += (node. item).toString() + node = node. link; + return 5; + Singura observatie pe care o facem aici este oi, desi metoda push din interfatd declari’ aruncarea unor exceptii de tipul StackException, nu este obligatorin ca metoda din clasti s& specifice si ea acest lucru, atat timp cat nu genereazi exceptii de acel tip. Invers este ins’ obligatoriu In continuare este prezentati o mic aplicatie demonstrativi care foloseste tipul de date nou creat si cele dou implementiir ale sale Listing 5.5: Polosirea public class TestStiva { ivel public static void afiseaza(Stack s) { System. out.println("Continutul stivei este: " + s); > public static void main(String args(I){ try € Stack si = new StackImpl1(); si.push ("a"); s1.push ("b"); afiseaza(st); Stack s2 = new StackImpl2(); 52. puch (new Integer (1)) ; 52. push (new Double (3.14)); afiseaza(s2); } catch (StackException e) { System.err.printin("Eroare 1a lucrul cu stiva!"); e.printStackTrace () ; Observati folosirea interfetei Stackca un tip de date, ce aduee flexibilitate sporit in manevrarea clasclor ce implementeaz tipul respectiv. Metoda 5,3, INTERFETE $I CLASE ABSTRACTE 129 afiseaza accept ca argument orice obiect al unei clase ce implementeazi Stack. Observatie In pachetul java.util exist clasa Stack care modeleazi notiune de stiv de obiecte si, evident, aceasta va fi folosit in aplicatille ce au nevoie de acest tip de date, Exemplu oferit de noi mu are legituri cu aceastit clasit gi are rol pur demonstratiy, 5.3 Interfete si clase abstracte La prima vedere o interfatii nu este altceva decat o clas abstract in care toate metodele sunt abstracte (nu au nici o implementare) Asadar, 0 clasié abstractii nu ar putea énlocui o interfatt ? Raspunsul la intrebare depinde de situatie, ins in general este “Nu? Deosebirea constis in faptul cl, unele clase sunt fortate si extindi o anumitit clasis (de exemplu orice applet trebuie sa fie subclasa a clasci Applet) gi nu ar mai putea sa extinda o alti clas, deoarece in Java nu exista decat mostenire simpla, Fara folosirea interfetelor nu am putea forta clasa respectiva si respecte diverse tipuri de protocoale. La nivel conceptual, diferenta const& in « extinderen unei clase abstracte forteazi o relatie intre clase; © implementarea unei interfete specific doar necesitatea implementarii unor anumie metode. In multe situatii interfetele si clasele abstracte sunt folosite impreunit pentru a implementa cat mai flexibil sieficient o anumiti ierarhie de clase, Un exemplu sugestiv este dat de clasele ce descriu colectii. Ca sa particularizim, existi: © interfata List care impune protocolul pe care trebuie si il respecte o clas’ de tip lists, @ clasa abstract’ AbstractList care implementeazii interfata List si fer’ implementiiri concrete pentru metodele comune tuturor tipurilor de lista, 130 CAPITOLUL 5. INTERFETE ¢ clase concrete, cum ar fi Linked List, ArrayList care extindAbstractList. 5.4 Mostenire multipla prin interfete Interfetele nu au nici o implementare si nu pot fi instantiate. Din acest motiv, nu reprezintii nici o problemi ca anumite clase si implementeze mai multe interfete sau ca o interfatii si extind®, mai multe interfete (s8 aib& mai multe superinterfete) class NumeClasa implements Interfatal, Interfata2, . interface lumeInterfata extends Interfatal, Interfata2, ... O interfati mosteneste atat constantele cat si declaratiile de metode de la superinterfetele sale. O clasi mosteneste doar constantele unei interfete si responsabilitatea implementiril metodelor sale. $i consideriim un exemplu de clasa care implementeaza mai multe interfete: interface Inotator { void inoata(); + interface Zburator { void zboara(); + interface Luptator { void lupta(}; + class Erou implements Inotator, Zburator, Luptator { public void inoata() {} public void zboara() {} public void lupta() {} + Exemplu de interfata care extinde mai multe interfete: interface Monstru { void ameninta(); } interface MonstruPericulos extends Monstru { void distruge(); 54, MOSTENIRE MULTIPLA PRIN INTERFETE 131 + interface Mortal { void omoara() ; + interface Vampir extends MonstruPericulos, Mortal { void beaSange() ; } class Dracula implements Vampir { public void ameninta() {} public void distruge() {} public void omoara()() {} public void beaSange() {} + Evident, pot apitea situatii de ambiguitate, atunci cand exist constante sau metode cu aceleasi nume in mai multe interfete, ins acest lucru trebuie intotdeauna evitat, deoarece scrierea unui cod care poate fi confuz este un stil prost de programare. In cazul in care acest lucru se intampla, compilatorul nut va furniza eroare decat deck se incearcit referiren constantelor ambigue far a le prefixa cu numele interfetel san daci metodele cu acelasi nume nu pot fi deosbite, cum ar fi situatia chnd au aceeasi list de argumente dar tipuri returnate incompatibile. interface I1 { int x-1; void metoda() ; } interface 12 { int x=2; void metoda(); //corect. /fint metoda(); //incorect } class C implements I1, 12 { public void metoda() { System.out.printIn(I1.x); //corect System.out.printIn(I2.x); //corect System.out.printla(x); //ambiguitate 132 CAPITOLUL 5. INTERFETE $i recapituliim eéteva lucruri legate de clase si interfete: ¢ 0 clas nu poate avea decat o superclass. ‘¢ 0 clast poate implementa orieate interfete. * 0 clasit trebuie obligatoriu si trateze metodele din interfetele pe care la implementenzi, ¢ Terarhia interfetelor este independent de ierarhia claselor care le im- plementeazi 5.5 Utilitatea interfetelor Dup cum am vézut, o interfata defineste un protocol ce poate fi implementat de orice clasi, indiferent de ierarhia de clase din care face parte, Interfetele sunt utile pentru: ‘¢ defininea unor similaritati intre clase independente fair a forta artificial © legaburi intre ele; ‘¢ sigur’ ci tonte clasele care implementea’ o interfat pun la dipozitie metodele specificate in interfat - de aici rezult&. posibilitatea imple- mentirii unor clase prin mai multe modalititi si folosirea lor intr-o manier unitar; dofinirea unor grupuri de constante; * transmiterea metodelor ca parametri; 5.5.1 Crearea grupurilor de constante Deoarece orice variabili a unei interfete este implicit declaratii cu public, staticsi final, interletele repreaint o metodié convenabilé de creare a unot grupuri de constante care si fie folosite global intr-o aplicatie: 5,5, UTILITATEA INTERFETELOR 133 public interface Luni { int IAN=1, FEB=2, ., DEC#=12; + Folosirea acestor constante se face prin expresii de genul NuneInterfata. constanta, ca in exemplul de mai jos if (luna < Luni .DEC) una ++ else Tuna = Luni. IAN; 5.5.2 Transmiterea metodelor ca parametri Deoarece nu existil pointeri propriu-zisi, transmiterea metodelor ca parametri este realizatii in Java prin intermediul interfetelor. Atunei cand o metodi trebuie si primeascX ca argument de intrare o referinti la o alti functie necesara exceutiei sale, cunoscuté doar Ia momentul executici, atunci argue mentul respectiv va fi declarat de tipul unei interfete care contine metoda respectivs. La executie metode va putea primi ca parametru orice obiect ce implementeazit interfata respectivi si deci contine si codul functiei respective, aceasta urmand st fie apelatit normal pentru a obtine rezultatul dorit. Aceastis tehnici, denumita si call-back, este extrem de folositit in Java si trebuie neapirat inteleast, $i consideriim mai multe exemple pentru a clarifier Inerurile Primul exemplu se refer Ia explorarea nodurilor unui graf. In fiecare nod trebuie sii se execute prelucrarea informatie’ din nodul respectiv prin intermediul nei funetii primite ca parametru. Pentru aceasta, vom defini o interfata Functie care va specifica metoda trimisi ca parametru. interface Functie { public void executa(lod u) ; } class Graf { Ws void explorare(Functie f) { Mane 134 CAPITOLUL 5. INTERFETE if (explorarea a ajuns in nodul v) { f.executa(w) ; Mews + + 3 //Definim doua functii class AfisareRo implements Functie { public void executa(Nod v) { System. out.println("Nodul curent este: " + v); + 3 class AfisareEn implements Functie { public void executa(Nod v) { System. out.println("Current node is: " + v); + 3 public class TestCallBack { public static void main(String args[]) { Graf G = new Graf(}; G.explorare(new AfisareRo()); G.explorare(new AfisareEn()); + } Al doilea xemplu va fi prezentat in sectiunea urmiitoare, intrucat face parte din API-ul standard Java si vor fi puse in evident, prin intermediul sin, si alte tehnici de programare. 5.6 Interfata FilenameFilter Instantele claselor ce implementeazi aceasta interfati sunt folosite pentru a crea filtre pentru fisiere si sunt primite ca argumente de metode care listeazit continutul unui director, cum ar fi metoda list a clasei File Asadar, putem spune ci metoda List primeste ca argument o alt functie care specific’ daci un fisier va fi returnat sau nu (criteriul de filtrare) 5.6, INTERFATA FILENAMEFILTER 135 Interfata FilenameFilter are o singuri metodi: accept care specific criterinl de filtrare si anume, testeazit daci numele fisierului primit ca para- metru indeplineste conditille dorite de noi Definitia interfetei este: public interface FilenameFilter { public boolean accept(File dir, String numeFisier); } Agadar, orice clasii de specifieare a unui filtrn care implementeza interfata FilenameFilter trebuie si implementeze metoda accept a acestei interfete. Aceste clase mai pot avea si alte metode, de exemplu un constructor care sk primeasca criteriul de filtrare, In general, o clas de specificare a unui filten are urmitornl format class FiltruFisiere implements FilenameFilter { String filtru; // Constructorul FiltruFisiere(String filtru) { this.filtra = filtru; } // Tuplenentarea metodei accept public boolean accept (File dir, String nume) { if (filtrul este indeplinit) return true; else return false; Metodele cele mai uzuale ale clasei String folosite pentru filtrarea figierelor sunt: ¢ endsWith - testeazi daci un sir are o anumitis terminatic @ indexOF- testeazd dacé un sir contine un anumit subgir, returnand pozitia acestnia, sau 0 in caz contrar 136 CAPITOLUL 5. INTERFETE Instantele claselor pentru filtrare sunt primite ca argumente de metode de listare a continutului unui director. O astfel de metoda este List din clasa File: String[] list (FilenameFilter filtru) Observati cf aici interiata este folositt ca un tip de date, ea find substi- tuiti cu orice clas care o implementeazi. Acesta este un exemplu tipic de transmitere a unei functii (functia de filtrare accept) ca argument al unci metode. $i considerim exemplul complet in care dorim si listiim fisierele din di- rectorul curent care au o anumiti extensie. Listing 5.6: Listarea figierelor cu o anumiti 7e Listarea fisierelor din directorul curent care au anumita extenste primta ca argument Daca nu se primeste nict un argument, vor fr listate toate ctensie 7 import java.io.+; class Listare { public static void main(String[] args) { try ¢ File director = new File(*."); Stringl] list; if (args. length > 0) list = director list (new Filtru(args[0])); else list = director .1ist(); for(int i = 0; i < list.length; i++) System. out. printin(List [4]) ; } catch(Exception e) { e.printStackTrace (); + class Filtru imploments FilenaneFilter { String extensie; Filtru (String extensie) { this.extensie = extensie; 5.6, INTERFATA FILENAMEFILTER 137, + public boolean accept (File dir, String nume) ¢ return ( nune.ends¥ith(7." + extensie) ); + + 5.6.1 Folosirea claselor anonime In caaul in care nu avem nevoie de clasa care reprezinti filtrul pentru listaren fisierelor dintr-un director deeat o singura dati, pentru a evita erearea unei noi clase de sine stittittoare care sé fie folosit pentru instantierea unui singur obiect, putem folosi class intern’ anonima, aceasta situatie fiind un exempla tipic de folosire a acestora. ing 5.7: Folosirea unei ch se Ano} /* Listarea fisterelor din directorul curent folosind o clasa anonima pentru siltru 7A import java.io.#; class Listare { public static void main(String[] args) ( try ¢ File director = new File(* String[] list; if (args.length > 0) { final String extensie = args (01; list = director. list (now FilenameFilter() ( // Clasa interna anonima public boolean accept (Fil dir, String nume) { + oxtensie) ) + bi + else list = director. list (); forCint i= 0; i < list. length; i++) System. out . printin (list (iJ); + cateh(Exception e) ¢ e.printStackTrace(); 138 CAPITOLUL 5. INTERFETE Asadar, o modalitate uzuala de folosire a claselor anonime pentru instantierea unui obiect care trebuie si respecte o interfata este: metoda(new Interfata() { // Iuplementarea metodelor interfetei wn; 5 Am vizut in primul capitol ci 0 solutie facili si eficientii de sortare a unui vector este folosiren metodei sort din clasa java-util Arrays. Compararea obiectelor int v[I=-(3, 1, 4, 23; java.util.arrays.sort(v); // Sorteaza vectorul ¥ // Acesta va deveni {1, 2, 3, 4} In cazul in care elementele din vector sunt de tip primitiv, ca in exem- plul de mai sus, nu existi nici o problema in a determina ordinea fireasc’ fa clementelor. Ce se intiimpl inst atunei cand vectorul contine referinte la obiecte de un anumit tip ? S& considerim urmétorul exemplu, in care dorim si sortim un vector format din instante ale clasei Persoana, definita mai jos: ing 5.8: class Persoana { int cod String nume; jasa Persoana (ffl suport pentru compara public Persoana(int cod, String nume) { this. cod this.nume public String toString() { return cod + * \t " + nume; » 5,7, COMPARAREA OBIECTELOR 139 Programul urmitor ar trebui si sorteze un vector de persoane: Listing 5.9 class Sortare { public static void main(String args[]) { Persoana p[] = new Persoana [4]; pl0] = new Persoana(3, "Ionescu"); pli] = new Persoana(1, "Vasilescu"); p[2] = new Persoana(2, "Georgescu p[3] = new Persoana(4, *Popescu"); rtarea unui vector de tip referinta java.util. Arrays. sort (p); System. out .printin("Persoanele ordonate dupa cod:"); for(int i=0; icp. length; i++) System. out .printia(pLil) ; La executia acestei aplicatii va fi obtinuti o exceptie, deoarece metoda sort nu stie care este ordinea natural a obiectelor de tip Persoana. Va trebui, intr-un fel sau altul, si specificiim acest Incru. 5.7.1 Interfata Comparable Interfata Comparable impune o ordine total asupra obiectelor unei clase ce © implementeazi, Aceastii ordine se numeste ordinea natural a clasei si este specificatis prin intermediul metodei compareTo. Definitia interfetei este: public interface Comparable { int compareTo (Object 0); } Agadar, o clasi ale cirei instante trebuie sii fle comparabil va implementa metoda compareTo care trebuie si returneze: @ 0 valoare strict negativa: daca obiectul curent (this) este mai mic deca obiectul primit ca. argument; # zero: daca obiectul curent este egal deca obiectul primit ca argument; 140 CAPITOLUL 5. INTERFETE @ o yaloare strict pozitiva: dacd obiectul curent este mai mare deca obiectul primit ca argument. Reamintim c& metoda equals, mosteniti din Object de toate clasele, determina daci dou’ obiecte sunt egale (au aceeasi valoare). Spunem ci ordinea. natural a unei clase C’ este consitentii cu equals daci si numai daci (¢1 .compareTo( (Object)e2) == 0) are aceeassi valoare logic cn e1 equals ((Object)e2, pentru orice el, €2 instante ale lui’ null nu este instanta a nici unei clase sie. compareTo(nul1) trebuie si arunce 0 exceptie de tip Nal 1PointerException chiar daci e equals(nul1) returneazié false. Si presupunem ci dorim ca ordinea natural a persoanelor si fie dup’ codul lor intern. Listing 5.10: Clasa Persoana cu suport pentru comparare class Persoana implements Comparable { int cod; String nume; public Persoana(int cod, String nume) { this.cod = cod: this.nume = nume; > public String toString( { return cod +" \t " + name; + public boolean equals (Object 0) { if ((o instanceof Persoana)) return false; Persoana p = (Persoana) 0; return (cod == p.cod) && (nune.equals(p.nume)); > public int compareTo(Object 0) € if (o==null) throw new NullPointerException(); if (1(o instanceof Persoana)) throw new ClassCastException("lu pot compara!™); Persoana p = (Persoana) 0; 5,7, COMPARAREA OBIECTELOR 141 return (cod - p.cod); + + Observati folosirea operatorului instanceof, care verificti dac un obiect este instanta a unei anumite clase. Metoda compareTo va arunca 0 exceptie de tipul ClassCastException daca se incearci compararea unui obiect de tip Persoana cu um obiect de alt tip. Metoda equals va returna, pur si simplu, false. 5.7.2 Interfata Comparator In cazul in care dorim s& sortm elementele unui vector ce contine referinte dupa alt criteriu decat ordinea natural a elemenetelor, avern nevoie de o altit solutie, Accasta este oferiti tot de metoda sort din clasa java.util. Arrays, dar in varianta in care, pe lang’ vectorul ce trebuie sortat, vorn transmite un argument de tip Comparator care sii specifice modalitatea de comparare a elementelor Interfata java.util.Comparator contine metodacompare, care impune o ordine total asupra elementelor unei colectii. Aceasta returneazi un intreg, cu aceeasi semnificatie ca la metoda compareTo a interfetei Comparator si are urmbtoarea definitie: int compare(Object o1, Object 02); SA presupunem ci dorim si sort persoanele ordonate dup, numele lor. Pentru definirea comparatorului vom folosi o clasi anonimi Listing 5.11: Sortarea unui vector folosind un comparator import java.util.¥; class Sortare { public static void main(String args([]) ¢ Persoana p[] = new Persoana(4]; pl0] = new Persoana(3, "Ionescu") pli] = new Persoana(1, "Vasilesc pl2] = new Persoana(2, "Georgesc p[3] = new Persoana(4, "Popescu"); Arrays.sort(p, new Comparator () { public int compare (Object of, Object 02) { Persoana pi = (Persoana)ot; Persoana p2 = (Persoana)o2; return (pi. nume.compareTo (p2.nume)) ; 142 CAPITOLUL 5. INTERFETE + wi System. out .printla("Persoanele ordonate dupa nume:"); for(int i=0; icp-length; i++) System. out. printla(plil) ; Observati cum compararea a dou siruri de caractere se face tot cu metoda compareTo, clasa String implemenand interfata Comparable. 5.8 Adaptori In cagul in care o interfati\ contine mai multe metode si, la un moment dat, avem nevoie de un obiect care implementeagt interfata respectiv dar mu specificd cod decat pentru o singur metodii, el trebui totusi si implementeze toate metodele interfetei, chiar dact, nu specific nici un cod. interface X { void metoda_1(); void metoda_2(); void metoda_n(); // hven nevoie de un obiect de tip X // ca argument al unei functii functie(new X() { public void metoda_i() { // Singura metoda care ne intereseaza + // Trebuie sa apara si celelalte metode // chiar daca nu au implementare efectiva public void metoda_2() {} public void metoda_3() {} public void metoda.n() {} 5,8. ADAPTORI 143 Ds Aceastii abordare poate fi neplicuti cack avem freevent nevoie de obiecte ale unor clase ce implementeazi interfata X. Solutia la aceastit problema este folosirea adaptorilor. Definitie Un adaptoreste o clasi abstractii care implementeazi o anumiti interfati farsa specifica cod nici unei metode a interfetei public abstract class XAdapter implements X { public void metoda_1() {} public void metoda_2() {} public void metodan() {} } In situatia cénd avem nevoie de un obiect de tip X vor folosi clasa abstracti, supradefinind doar metoda care ne intereseazh: functie(new XAdapter() { public void metoda_i() { // Singura metoda care ne intereseaza oc D: Mai multe exemple de folosire a adaptorilor vor fi date in capitolul *Interfata grafica cu utilizatorul” 144 CAPITOLUL 5. INTERFETE Capitolul 6 Organizarea claselor 6.1 Pachete Definitie Un pachet este o colectie de clase gi interfete inrudite din punetul de vedere al functionalititii lor. Sunt folosite pentru gisirea si utilizarea mai ugoarii a claselor, pentru a evita conflictele de nume si pentru a controla agcesul Ia anumite clase. In alte limbaje de programare pachetele se mai numese librarii sau bibilioteci, 6.1.1 Pachetele standard (J2SDK) Platforma standard de lucru Java se bazeazi pe o serie de pachete cu ajutorul cirora se pot construi intr-o manier’ simplificati aplicatiile. Exist deci un set de clase deja implementate care modeleaza structuri de date, algoritn diverse notiuni esentiale in dezvoltarea unui program. Cele mai importante pachete si suportul oferit de lor sunt sau @ java.lang - clasele de baza ale limbajului Java ¢ java.io - intrari/iegiri, Incrul cu figiere © java.util - clase gi interfete utile ¢ java.applet - dezvoltarea de appleturi 145 146 CAPITOLUL 6. ORGANIZAREA CLASELOR ¢ java.awt - interfata grafied cu utilizatorul ¢ java.awt.event - mecanismele de tratare e evenimentelor generate de utilizator ¢ java. beans - scrierea de componente reutilizabile # java.net - programare de reten # java.sql- lucrul cu baze de date ¢ java.rmi- executie la distant’ Remote Message Interface ¢ java.security- mecanisme de securitate: criptare, autentifieare ¢ java.math - operatii matematice cu numere mari ¢ java.text - lucrul cu texte, date si mumere independent de limbi @ java.lang.reflect - introspectie ¢ javax.swing- interfata grafic cu utilizatorul, mult imbogitit fata de AWT, ee 6.1.2 Folosirea membrilor unui pachet Conform specificatillor de acces ale unei clase si ale mebrilor ei, doar clasele publice si membrii declarati publici ai unei clase sunt accesibili in afara pa chetului in care se gisesc. Dup’ cum am vizut in sectiunea *Specificatori de acces pentru membrii unei clase”, accesul implicit: in Java este la. nivel de pachet, Pentru a folosi o clas publick dintr-un anumit pachet, sau pentru a apela o metod publica a unei clase publice a unui pachet, exist’ trei solutii specificarea numelui complet al clasei @ importul clasei respective ¢ importul intregului pachet in care se giseste clasa 6.1, PACHETE 147 Specificarea numelui completal clasei se face prin prefixarea numelui seurt al clasei cu numele pachetului din care face parte: numePachet . NuneClasa. Button = numele scurt al clasei java.awt - pachetul din care face parte java.awt.Button - nunele complet al clasei Aceastii metoda este recomandat doar pentru cazul in care folosiren acelei clase se face o singur dati sau foarte rar. De exemplu, ar fi extrem de neplicut sii scriem de fiecare data cind vrem sii declariim un obiect grafic secvente de genu!: java.awt.Button bi = new java.awt.Button("0K") ; java.awt.Button b2 - new java.awt Button("Cancel") ; java.awt. TextField tf1 = new java.awt.TextField("Neplacut") ; java.awt. TextField tf2 - new java.awt.TextField(*Tot neplacut") ; In aceste situatii, vom importa in aplicatia noastr’ clasa respectiva, sau intreg pachetul din care face parte. Acest lncru se realizeaza prin instructiumea import, care trebuie st aparé la inceputul fisierelor sursé, inainte de declararea vreunei clase sau interfete. 6.1.3 Importul unei clase sau interfete Se face prin instructiunea import in care specificim numele complet al clase sau interfetel pe care dorim si o folosim dintr-un anumit pacehet: import numePachetnumeClasa; //Pentra exemplul nostru: import java.awt Button; import java.awt.TextFiel Din acest moment, vorn putea folosi in clasele fisierului in care am plasat instructiunea de import numele scurt al claselor Button gi TextField: Button bi = new Button("OK"); Button b2 = new Button("Cancel") ; TextField tf1 = new TextField(*Placut"); TextField tf2 = new TextField("Foarte placut") ; 148 CAPITOLUL 6. ORGANIZAREA CLASELOR ‘Aceasti abordare este eficientit si recomandati\ in cazul fn care nu aver nevoie deciit de cdteva clase din pachetul respectiy. Dac in exemplul nostru am avea nevoie si de clasele Line, Point, Rectangle, Polygon, ar trebui si avem cate o instructiune de import pentru fiecare dintre ele: import java.awt.Button; import java.awt.TextField; import java.awt Rectangle; import java.awt.Line; import java.awt.Point; import java.awt Polygon; In aceasta situatie ar fi mai simplu si folosim importul la cerere din intregul pachet si nu al fiecirei clase in parte. 6.1.4 Importul la cerere dintr-un pachet Importul la cerere dintr-un anumit pachet se face printr-o instructiune import in care specificim numele pachetului ale cirui clase si interfete dorim sit le folosim, urmat de simbolul *, Se numeste import la cerere deoarece incircarea claselor se face dinamie, in momentul apelatti lor. import numePachet.*; //Pentru exenplul nostru: import java.awb.*; Din acest moment, vom putea folosi in clasele figierului in care am plasat instructiunea de import numele scurt al tuturor claselor pachetului importat: Button b = new Button("OK"); Point p = new Point(0, 0); Atentie * nu are semnificatia uzuali de la fisiere de wildeard (masci) gi nu poate fi folosit decat ca atare. O expresie de geuul import java.awt.Cs; va produce © eroare de compilare 6.1, PACHETE 149 In cazul in care sunt importate dou sau mai multe pachete care contin clase (interfete) cu acelagi nume, atunci referirea la ele trebuie facut doar folosind numele complet, in caz contrar fiind semnalati 0 ambiguitate de catre compilator. import java.awt.*; // Contine clasa List import java.util.*; // Contine interfata List List x; //Declaratie ambigua java.awt.List a java.util.List b new java.awt.List(); //corect new ArrayList(); //corect Sunt considerate importate automat, pentru orice fier sursa, urmitoarele pachete © pachetul java. lang import java.lang.+; // Poate sau nu sa apara // Wai bine nu. © pachetul curent © pachetul implicit (firs nume) 6.1.5 Importul static Aceastit facilitate, introdusti incepand cu versiunea 1.5, permite referirea con- stantelor statice ale unei clase firii a mai specifica numele complet al aces- teia gi este implementata prin adiugarea cuvantului cheie static dupa cel de import: import static numePachet:.NumeClasa.+; Astfel, in loc si ne referim la constantele clasei cu expresii de tipul MNumeClasa.CONSTANTA, putem folosi doar numele constantei, 150 CAPITOLUL 6. ORGANIZAREA CLASELOR // Tnainte de versiuna 1.5 import java.awt.BorderLayout.*; fereastra.add(new Button(), BorderLayout CENTER) ; // Tncepand cu versiunea 1.5 import java.awt.BorderLayout.*; import static java.awt BorderLayout.+; fereastra.add(new Button(), CENTER); Atentie Importul static nu import decét constantele statice ale unei clase, nu gi clasa in sine. 6.16 Crearea unui pachet Toate clasele si interfetele Java apartin la diverse pachete, grupate dup functionalitatea lor. Dup& cum am vazut clasele de baz se gisese in pa- chetul java. lang, clasele pentru intrari iesiri sunt in java. io, clasele pentru interfata grafic in java awt, ote. Crearea unui pachet se realizeaz prin scriere la inceputul fisierelor sursit ce contin clasele si interfetele pe care dorim s& le grupim intr-un pachet a instructiunii: package numePachet: $i consideriim un exemplu: presupunem ci avem dou figiere sursi Graf . java si Arbore. java. //Fisierul Graf. java package grafuri; class Graf {...} class GrafPerfect extends Graf {...} //Fisierul Arbore. java package grafuri; class Arbore {...} 6.1, PACHETE 151 class ArboreBinar extends Arbore {...} Clasele Graf, GrafPerfect, Arbore, ArboreBinar vor face parte din acelagi pachet grafuri. Instructiuneapackage actioneazii asupra intregului figier sursi la inceputul cfruia apare, Cu alte cuvinte nu putem specifica faptul ci anumite clase dintr-un figier sursa apartin unui packet, iar altele altui pachet Dacit nu este specificat un anumit pachet, clasele unui fisier sursii vor face parte din pachetul implicit (care nu are nici un nume}. In general, pachetul implicit este format din toate clasele si intefetele directorului curent de lucru. Este recomandat: insé ca toate clasele si intefetele sa fie plasate in pachete, pachetul implicit fiind folosit doar pentru aplicatii mici sau prototipuri 6.1.7 Denumirea unui pachet Exist posibilitatea ca doi programatori care lucreaz Ia un proiect comun. si foloseasc’ acelagi nume pentru unele din clasele lor. De asemenea, se poate ca una din clasele unei aplicatii si aib& acelagi nume cu o clasé a mediului Java. Acest lucru este posibil atat timp cat clasele cu acelasi nume se gasesc in pachete diferite, ele fiind diferentiate prin prefixarea lor cu numele pachetelor. Ce se intémpli insti cand doi programatori care Inereazii la un protect comun folosese clase cu acelagi nume, ce se gasese in pachete cu acelasi nume Pentru a evita acest lucru, companiile folosesc inversul domeniului lor Internet in denumirea pachetelor implementate im cadrul companiei, cum ar firro.companie.numePachet. In cadrul aceleiasi companii, conflictele de nume vor fi rezolvate prin diverse conventii de uz intern, cum ar fi folosiren numelui de cont al programatorilor in denumirea pachetelor create de acestia, De exemplu, programatorul cu numele Jon al companiei XSoft, avand contul ionQxsoft.r0, isi va prefixa pachetele cu ro.xsoft.ion, pentru a permite identificarea in mod unic a claselor sale, indiferent de contextul in care acesten vor fi integrate. 152 CAPITOLUL 6. ORGANIZAREA CLASELOR 6.2 Organizarea fisierelor 6.2.1 Organizarea figierelor sursi Orice aplicatie nebanali trebuie si fie construité folosind o organizare ier- arhici a componentelor sale, Este recomandat ca strategia de organizare a fisierelor sursit si respecte urmitoarele conventii: ‘¢ Codul sursi al claselor si interfetelor st se gaseascl in figiere ale citror nume si fie chiar numele lor sourt si care sh alibi extensia java Atentie Este obligatoriu ca o clasi/interfati public si se gaseascf intr-un fisicr avand numele clasei(interfetei) si extenisa . java, sau compilatorul va furniza o eroare. Din acest motiy, intr-un fisier surs nu pot exista dont clase sau interfete publice. Pentru clasele care nu sunt publice acest lucru nu este obligatoriu, ci doar recomandat. Intr-un figier sursi pot exista oricdte clase sau interfete care nu sunt publice, «¢ Fisierele sursii trebuie si se giseascl in directoare care si reflecte nu- mele pachetelor in care se gisese clasele si interfetele din acele fisiere. Cu alte cuvinte, un director va contine surse pentru clase gi interfete din acelasi pachet iar numele directorului va fi chiar numele pachetu- ui, Dack numele pachetelor sunt formate din mai multe unitati lexicale separate prin punct, atunci acestea trebuie de asemenea si corespunda unor directoare ce vor descrie calea spre fisierele sursi ale chror clase si interfete fac parte din pachetele respective. Vom clarifica modalitatea de organizare a fisierelor sursit ale unei aplicatii printr-un exemplu coneret. Si presupunem ci dorim crearea unor compo- nente care si reprezinte diverse notiuni matematice din domenii diferite, cum ar fi geometrie, algebri, analiza, etc. Pentru a simplifica lucrurile, si presupunem ca dorim sii cream clase care sii descrie urmittoarele notiuni: poligon, cere, poliedru, sferd, grup, funcfie. prima varianta ar fis construim céte o clas pentru fiecare si si le plasm 6.2, ORGANIZAREA FISIERELOR 153, in acelasi director impreuna cu un program care si le foloseasea, insti, avand in vedere posibila extindere a aplicatiei cu noi reprezentiri de notiuni matem- atice, aceasté abordare ar fi ineficienti © abordare elegant’ ar fi aceea in care clasele care descriu notiuni din acelagi domeniu sa se gaseasca in pachete separate si directoare separate. Ierarhie fisierelor sursa ar fi /matenatica /surse /geonetrie ‘/plan Poligon. java Gere. java /spatiu Poliedru. java Sfera. java /algebra Grup. java /analiza Functie. java Matematica. java Clasele descrise in figierele de mai sus trebuie declarate in pachete denu- mite corespunzator cu numele directoarelor in care se gasesc: // Poligon. java package geometrie.plan; public class Poligon {. . . } // Cerc.java package geonetrie.plan; public class Cere { . } // Poliedru. java package geometrie .spatiu; public class Poliedru{ . . . } 154 CAPITOLUL 6. ORGANIZAREA CLASELOR // Sfera.java package geometrie.spatiu; public class Sfera { } // Grup. java package algebra; public class Grup { } // Functie. java package analiza; public class Functie { . . . } Matematica. java este clasa principal a aplicatiei Dupi cum se observa, numele nng al unei clase trebuie si desorie ealea spre acea clasi in cadrul fisierelor suri, relativ la directorul in care se gliseste aplicatia 6.2.2 Organizarea unititilor de compilare (.class) In urma compiliil fiierelor surst vor fi generate unititi de compilare pentru fiecare clash sl interfaté din fisierele sursi, Dup’ cum stim acestea au extensia .class si numele scurt al clasei sau interfetei respective. Spre deosebire de organizarea surselor, un fisier .class trebuie si se gaseasca intt-o ierarhie de directoare care si reflecte numele pachetului din care face parte clasa respectiva, Implicit, in urma compilatii figierele sursi gi unititile de compilare se giisese in acelasi director, ins ele pot fi apoi organizate separat. Este reco- mandatinsii ca aceasta separare si fie facut’ automat la compilare. Revenind Ia exemplul de mai sus, vor avea urmitoarea orgonizate /natematica /clase /geonetrie /plan Poligon.class Gerc.class /spatiu 6.2, ORGANIZAREA FISIERELOR 155, Poliedru.class Sfera.class /algebra Grup. class /analiza Functie.class Matematica. class Crearea acestei structuri ierarhice este facut’ automat de catre compilator. In directorul aplicatici (matematica) credim subdirectorul clase si dim co- manda: javac -sourcepath surse surse/Matematica.java -d clase sau javac -classpath surse surse/Matematica.java -d clase Optiunea -d specific directorul ridiicind al ierarhiei de clase. In lipsa lui, fiecare unitate de compilare va fi plasatit in acelasi director cu fisierul si sursi. Deoarece compilim clasa principal a plicatiei, vor fi compilate in cascadit toate clasele referite de aceasta, dar numai acestea, In cazul in care dorim si compilim explicit toate fislerele java dintr-un anumit director, de exempla surse/geometrie/plan, putem folosi expresia’ javac surse/geometrie/plan/*. java -d clase 6.2.3 Necesitatea organizirii fisierelor Organizarea figierelor sursi este necesard deoarece in momentul cénd compi- latoru! intalneste un nume de clasi el trebuie sti poati identifica acea clast, ceea ce inseamna ci trebuie si gaseasc’ figerul sursi care o contine. Similar, unitatile de compilare sunt organizate astfel pentra a da posibil- itatea interpretorului si gaseasca si si inearce in memorie o anumit clas’ in timpul executiei programului Ins aceasti organizare nu este suficienti deoarece specific numai partea finalit din calea cdtre fisierele java si .class, de exemplu /matematica/clase/geometrie/plan/Poligon.class. Pentru aceasta, atat Ja compilare eat si Ia interpretare trebuie specifica lista de directoare r&dacin’ 156 CAPITOLUL 6. ORGANIZAREA CLASELOR in care se gisesc fisierele aplicatiel. Aceasti list se numeste cale de cautare (classpath). Definitie O cale de citutareeste o list de directoare sau arhive in care vor fi clutate fisierele necesare unei aplicatii. Flecare director din calea de cautare este directorul imediat superior structurii de directoare corespunzitoare numelor pachetelor in care se gisesc clasele din directorul respectiv, astfel incat compi- latoral si interpretorul s& poat construi calea complet spre clasele aplicatiei Implicit, calea de ciutare este format doar din directorul curent. $i consideriim clasa principaltt a aplicatiei Matematica. java: import geometrie.plan.*; import algebra Grup; import analiza.Functie; public class Matematica { public static void main(String args[]) { Poligon a = new Poligon(); geonetrie.spatiu.Sfera = new geometrie.spatiu.Sfera(); Hee + 3 Identificarea unei clase referite in program se face in felul urmétor * La directoarele aflate in calea de c&utare se adaugi subdirectoarele specificate in import sau in numele lung al clasei ‘@ In directoarele formate este ciutat un figier cu numele clasei. In cagul in care nu este gasit nici unul sau sunt gasite mai multe va fi semnalata © eroare. 6.2.4 Setarea cAii de ciutare (CLASSPATH) Setarea caii de cButare se poate face in doud modalitiiti ¢ Sotarea variabilei de medin CLASSPATH - folosind aceastil variant toate aplicatiile Java ce pe magina respectivé vor cRuta clasele necesare in directoarele specificate in variabila CLASSPATH. 63, ARHIVE JAR 15) UNIX: SET CLASSPATH = calet:cale2:... DOS shell (Windows 95/NT/...): SET CLASSPATH = calet;cale2;. « Folosirea optiunii-classpath la. compilarea si interpretarea programelor = directoarele specificate astfel vor fi valabile doar pentru comanda curentis javac - classpath java - classpath Lansarea in executie a aplicatiei noastre, din directorul matematica, se va face astiel java ~classpath clase Matematica In conoluzie, o organizare eficienti a figierelor aplicatie’ ar arita astfel /matematica /surse /clase compile.bat (javac -sourcepath surse surse/Matematica.java -d clase) run. bat (java -classpath clase Matematica) 6.3 Arhive JAR Fisierele JAR (Java Archive) sunt arhive in format ZIP folosite pentru impachetarea aplicatiilor Java. Ele pot fi folosite si pentru comprimari obignuite, diferenta fath de o arhiva ZIP obismuiti fiind doar existenta unui director denumit META-INE, ce contine diverse informatii auxiliare legate de aplicatia sau clasele arhivate Un fisier JAR poate fi creat folosind utilitarul jar aflat in distributia J2SDK, sau metode ale claselor suport din pachetul java.util.jar. Dintre beneficiile oferite de arhivele JAR amintim © portabilitate - este un format de arhivare independent de platform; 158 CAPITOLUL 6. ORGANIZAREA CLASELOR ‘© compresare - dimensiunea unei aplicatii in forma sa finalit este redusi; ‘* minimizarea timpului de incarcare a unui applet: dack appletal (fisiere class, resurse, ete) este compresat intr-o arhivi JAR, el poate fi incircat ‘intr-o singurd tranzactie HT'TP, fori a fi deci nevoie de a deschide eate © conexiune noua pentru fiecare figier; securitate - arhivele JAR pot fi ”semnate” electronic ‘¢ mecanismul pentru lucrul cu figiere JAR este parte integrata a plat- formei Java, 6.3.1 Folosirea utilitarului jar Arhivatorul jar se giseste in subdirectorul bin al directorulai in care este instalat kitul J2SDK. Mai jos sunt prezentate pe scurt operatille uzuale: © Crearea nnei arhive jar cf arhiva.jar figier(e)-intrare ¢ Vizwalizare continutului jar tf nume-arhiva ¢ Extragerea continutului jar xf arhiva.jar © Extragerea doar a unor figiere jar xf arhiva.jar figier(e)-arhivate Executarea unei aplicatii java -jar arhiva. jar Deschiderea unui applet arhivat Exemple: © Arhivarea a doul fisiere class jar cf classes. jar A.class B.class arhivarea tuturor fisierelor din directorul curent: jar cv allfiles.jar + 63, ARHIVE JAR 159 6.3.2 Executarea aplicatiilor arhivate Pentru © rula o aplicatie impachetati intr-o arhivi JAR trebuie si facem cunoscuta interpretorului numele clasei principale a aplicatiei. S& considers urmitorul exemplu, in cate dorim si arhivim clasele aplicatiei descrise mai sus, in care clasa principal’ eraMatematica.java. Din directorul clase vom Jansa comanda: jar ovf mate.jar geometrie analiza algebra Matematica.class In urma acestei comenzi vom obtine athiva mate. jar. Dac’ vom incerca si lanstim in executie aceasti arhivit prin comanda java ~jar mate. jar vom obtine urmitoarea eroare: "Failed to load Main-Class manifest from mate.jar’. Aceasta inseamna ci in fiserul Manifest.mf ce se gaseste in di- rectorul META-INF trebuie si inregistriim clasa principalit a aplicatiei. Acest ueru il vorn face in doi past: se creeagii un fisier cu un nume oarecare, de exemplu manifest txt, in care yom serie’ Main-Class: Matematica adaugim aceastit informatie la fisierul manifest al arhivel mate,jar jar uvfm mate. jar manifest txt Ambele operatii puteau fi executate intr-un singur pas: jar cvfm mate. jar manifest.txt geometrie analiza algebra Matematica.class Pe sistemele Win32, platforma Java 2 va asocia extensiile jar cu inter- pretorul Java, ceea ce inseamni ci facind dublu-click pe o arhivé JAR va fi lansati in executie aplicatia impachetatd in acea arhivé (dack exist o clas principala).

S-ar putea să vă placă și