Sunteți pe pagina 1din 121

FIFOR CARMEN

PROGRAMARE ORIENTAT OBIECT


Material de studiu pentru nvmntul la distan

Specializarea: Informatic, Anul II

Arad, 2010

Cuprins
Prefa .................................................................................................................................................. 3 I. Introducere n Java ............................................................................................................................ 5 1.1 Ce este Java ? ............................................................................................................................. 5 1.2 Primul program .......................................................................................................................... 7 1.3 Structura lexical a limbajului Java ........................................................................................... 8 1.4 Tipuri de date i variabile......................................................................................................... 11 1.5 Controlul execuiei ................................................................................................................... 13 1.6 Tipuri enumerate (enum).......................................................................................................... 16 1.7 Folosirea argumentelor de la linia de comand........................................................................ 17 II. Elemente de baz ale programarii orientate obiect........................................................................ 21 2.1 Clase i obiecte............................................................................................................................. 21 2.1.1 Crearea claselor ..................................................................................................................... 21 2.1.2 Clase imbricate ...................................................................................................................... 28 2.1.3 Crearea obiectelor ................................................................................................................. 30 2.1.4 Membri de instan i membri de clas ................................................................................. 32 2.1.5 Tablouri ................................................................................................................................. 33 2.1.6 iruri de caractere ................................................................................................................. 35 2.2 Motenirea .................................................................................................................................... 40 2.2.1 Ce este motenirea? ............................................................................................................... 40 2.2.2 Suprancrcarea i supradefinirea metodelor ........................................................................ 40 2.2.3 Clasa Object .......................................................................................................................... 41 2.2.4 Clase i metode abstracte ...................................................................................................... 43 2.2.5 Interfee ................................................................................................................................. 45 2.2.6 Adaptori ................................................................................................................................ 49 2.2.7 Polimorfism ........................................................................................................................... 49 2.3 Excepii ........................................................................................................................................ 54 2.3.1 Ce sunt excepiile ? ............................................................................................................... 54 2.3.2 Ierarhia claselor ce descriu excepii ...................................................................................... 55 2.3.3 Prinderea i tratarea excepiilor ......................................................................................... 55 2.3.4 Aruncarea excepiilor de ctre o metod ........................................................................... 57 2.3.5 Avantajele tratrii excepiilor................................................................................................ 58 2.3.6 Excepii la execuie ............................................................................................................... 58 2.3.7 Excepii definite de utilizator ................................................................................................ 58 2.4 Intrri i ieiri. Fluxuri ................................................................................................................. 60 2.4.1 Introducere ............................................................................................................................ 60 2.4.2 Fluxuri primitive ................................................................................................................... 62 2.4.3 Fluxuri de procesare .............................................................................................................. 62 2.4.4 Crearea unui flux ................................................................................................................... 63 2.4.5 Fluxuri pentru lucrul cu fiiere .............................................................................................. 64 2.4.6 Citirea i scrierea cu buffer ................................................................................................... 65 2.4.7 Clasele DataInputStream i DataOutputStream .................................................................... 66 2.4.8 Fluxuri standard de intrare i ieire ....................................................................................... 67 2.4.9 Intrri i ieiri formatate ........................................................................................................ 68

2.4.10 Clasa RandomAccesFile (fiiere cu acces direct) ............................................................... 70 2.4.11 Clasa File ............................................................................................................................ 72 2.5 Colecii ......................................................................................................................................... 75 2.5.1 Introducere ............................................................................................................................ 75 2.5.2 Interfee ce descriu colecii ................................................................................................... 75 2.5.3 Implementri ale coleciilor .................................................................................................. 78 2.5.4 Folosirea eficient a coleciilor ............................................................................................. 79 2.5.5 Algoritmi polimorfici ............................................................................................................ 80 2.5.6 Tipuri generice ...................................................................................................................... 80 2.5.7 Iteratori i enumerri ............................................................................................................. 81 III. Operatii speciale asupra claselor si obiectelor ...................................................................... 86 3.1 Serializarea obiectelor .................................................................................................................. 86 3.1.1 Folosirea serializrii .............................................................................................................. 86 3.1.2 Obiecte serializabile .............................................................................................................. 89 3.1.3 Personalizarea serializrii obiectelor .................................................................................... 90 3.2 Fire de execuie ............................................................................................................................ 95 3.2.1 Introducere ............................................................................................................................ 95 3.2.2 Crearea unui fir de execuie .................................................................................................. 96 3.2.3 Ciclul de via al unui fir de execuie ................................................................................... 99 3.2.4 Comunicarea prin fluxuri de tip pipe .............................................................................. 102 3.3 Organizarea claselor................................................................................................................... 105 3.3.1 Pachete ................................................................................................................................ 105 3.3.2 Organizarea fiierelor.......................................................................................................... 108 3.3.3 Arhive JAR ......................................................................................................................... 111 3.3.4 javadoc ................................................................................................................................ 112 Rspunsuri la testele de evaluare ..................................................................................................... 115

Programare orientat obiect Prefa

Ce nseamn Programarea orientat pe obiecte (POO)?


Programarea orientat obiect este unul din cei mai importani pai fcui n evoluia limbajelor de programare spre o mai puternic abstractizare n implementarea programelor. ntrebarea este: la ce se refer aceast abstractizare cnd vine vorba de un limbaj de programare? Ea a aparut din necesitatea exprimarii problemei ntr-un mod mai natural fiinei umane. Astfel unitile care alctuiesc un program se apropie mai mult de modul nostru de a gndi dect modul de lucru al calculatorului. Pn la apariia programrii orientate obiect, programele erau implementate n limbaje de programare procedurale (C, Pascal) sau n limbaje care nici mcar nu ofereau o modalitate de grupare a instruciunilor n uniti logice (functii, proceduri) cum este cazul limbajului de asamblare (assembler). Altfel spus, o problem preluat din natur trebuia fragmentat n repetate rnduri, astfel nct s se identifice elementele distincte, implementabile ntr-un limbaj de programare. O mare problem a programrii procedurale era separarea datelor de unitile care prelucrau datele (subrutinele), ceea ce facea foarte dificil extinderea i ntreinerea unui program. Astfel, s-a pus problema ca aceste dou entiti (date i subrutine) s fie grupate ntr-un anumit mod, astfel nct subrutinele s "tie" n permanen ce date prelucreaz i, mai mult dect att, ele s formeze un modul, adic o unitate care separ implementarea de interfa, ceea ce implic posibilitatea refolosirii codului. A aparut astfel conceptul de clas. Clasa grupeaz datele i unitile de prelucrare a acestora ntr-un modul, unindu-le astfel ntr-o entitate mult mai natural. Dei tehnica se numete "Programare Orientata Obiect", conceptul de baz al ei este este Clasa. Clasa, pe lng faptul c abstractizeaz foarte mult analiza/sinteza problemei, are proprietatea de generalitate, ea desemnnd o mulime de obiecte care mpart o serie de proprieti comune. De exemplu: Clasa "floare" desemneaz toate plantele care au flori, precum clasa "Fruct" desemneaz toate obiectele pe care noi le identificam ca fiind fructe. Binenteles, n implementarea efectiv a programului nu se lucreaz cu entitati abstracte, precum clasele ci se lucreaz cu obiecte, care sunt "instanieri" ale claselor. Altfel spus, plecnd de la exemplul de mai sus, dac se construiete un program care s lucreze cu fructe, el nu va prelucra entitatea "fruct" ci va lucra cu entiti concrete ale clasei "fruct", adic "mr", "par", "portocal", etc. Odat identificate entitile (n spe clasele) ele nu rmn izolate; ele vor fi grupate n module, pachete, programe, etc., care vor stabili legaturi ntre ele. Aceste legturi reflect relaiile care se stabilesc ntre clasele/obiectele problemei pe care am preluat-o din natur. Ideea POO este de a vedea programele ca o colecie de obiecte, uniti individuale de cod care interacioneaz unele cu altele, n loc de simple liste de instruciuni sau de apeluri de proceduri. Principiile de baz ale POO: - Abstractizarea - ncapsularea - Polimorfismul - Motenirea Note

Programare orientat obiect

Note

Programare orientat obiect I. Introducere n Java

Obiective: Cunoaterea structurii lexicale a limbajului Java (identificatori, terea literali, cuvinte cheie) Cunoaterea operatorilor Java i a modului corect de folosire a terea i lor Cunoaterea tipurilor de date primitive terea Cunoaterea setului de instruc iuni de control si modul corect instruciuni de folosire a lor Cunoaterea modului de lucru cu argumentele transmise din terea linia de comand 1.1 Ce este Java ? Java este o tehnologie inovatoare lansat de compania Sun Microsystems lansat n 1995, care a avut un impact remarcabil asupra ntregii comunit comuniti a dezvoltatorilor de software, impunndu impunndu-se prin caliti deosebite cum ar fi i simplitate, robustee i nu n ultimul rnd portabilitate. Denumit iniial OAK, i Denumit ial tehnologia Java este format dintr dintr-un limbaj de programare de nivel nalt pe baza aj cruia sunt construite o serie de platforme destinate implement rii de aplica ruia implementrii aplicaii pentru toate segmentele industriei software.

1.1.1 Limbajul de programare Java


Inainte de a prezenta n detaliu aspectele tehnice ale limbajului Java, sa amintim caracteristicile sale principale, care l l-au transformat ntr-un interval de un timp att de scurt ntr-una din cele mai populare op iuni pentru dezvoltarea de una opiuni aplicaii, indiferent de domeniu sau de complexitatea lor. ii, Simplitate - elimina suprancarcarea operatorilor, mo tenirea multipla toate motenirea i facilitaile ce pot provoca scrierea unui cod confuz. ile Uurina n crearea de aplicaii complexe ce folosesc programarea n reea, fire a aplicaii de execuie, interfaa grafica, baze de date, et a etc. Robustee - elimin sursele frecvente de erori ce apar n programare prin renunarea la pointeri, administrarea automat a memoriei i eliminarea area automat i pierderilor de memorie printr-o procedura de colectare a obiectelor care nu mai -o sunt referite, ce ruleaza n fundal (garbage collector). Complet orientat pe obiecte - elimin complet stilul de programare procedural. Securitate - este un limbaj de programare foarte sigur, furniznd mecanisme stricte de securitate a programelor concretizate prin: verificarea dinamica a verificarea codului pentru detectarea secven elor periculoase, impunerea unor reguli stricte secvenelor pentru rularea proceselor la distan etc. distana, Neutralitate arhitectural - comportamentul unei aplica ii Java nu depinde de aplicaii arhitectura fizic a mainii pe care ruleaz. inii Portabililtate - Java este un limbaj independent de platforma de lucru, aceea aceeai aplicaie rulnd fr nici o modificare i fr a necesita recompilarea ei pe sisteme de operare diferite cum ar fi Windows, Linux, Mac OS, Solaris, etc. lucru care aduce economii substaniale firmelor dezvoltatoare de aplica iale aplicaii. Este compilat i interpretat, aceasta fiind solu i soluia eficient pentru ob obinerea portabilitaii.

Note

Programare orientat obiect Performana - dei mai lent dect limbajele de programare care genereaz executabile native pentru o anumit platform de lucru, compilatorul Java asigur o performan ridicat a codului de octei, astfel nct viteza de lucru puin mai scazut nu va fi un impediment n dezvoltarea de aplicaii orict de complexe, inclusiv grafica 3D, animaie, etc. Este modelat dup C i C++, astfel trecerea de la C, C++ la Java facndu-se foarte uor.

1.1.2 Platforme de lucru Java


Limbajul de programare Java a fost folosit la dezvoltarea unor tehnologii dedicate rezolvarii unor probleme din cele mai diverse domenii. Aceste tehnologii au fost grupate n aa numitele platforme de lucru, ce reprezinta seturi de librarii scrise n limbajul Java, precum i diverse programe utilitare, folosite pentru dezvoltarea de aplicaii sau componente destinate unei anume categorii de utilizatori. J2SE (Standard Edition): Este platforma standard de lucru ce ofer suport pentru crearea de aplicaii independente i appleturi. De asemenea, aici este inclus i tehnologia JavaWeb Start ce furnizeaz o modalitate extrem de facil pentru lansarea i instalarea local a programelor scrise n Java direct de pe Web, oferind cea mai comod soluie pentru distribuia i actualizarea aplicaiilor Java. J2ME (Micro Edition): Folosind Java, programarea dispozitivelor mobile este extrem de simpl, platforma de lucru J2ME oferind suportul necesar scrierii de programe dedicate acestui scop. J2EE (Enterprise Edition): Aceast platform ofer API-ul necesar dezvoltrii de aplicaii complexe, formate din componente ce trebuie s ruleze n sisteme eterogene, cu informaiile memorate n baze de date distribuite, etc. Tot aici gsim i suportul necesar pentru crearea de aplicaii i servicii Web, bazate pe componente cum ar fi servleturi, pagini JSP, etc. Toate distribuiile Java sunt oferite gratuit i pot fi descarcate de pe Internet de la adresa http://java.sun.com. n continuare, vom folosi termenul J2SDK pentru a ne referi la distribuia standard J2SE 1.5 SDK (Tiger).

1.1.3 Java: un limbaj compilat i interpretat


n funcie de modul de execuie a aplicaiilor, limbajele de programare se mpart n doua categorii: Interpretate: instruciunile sunt citite linie cu linie de un program numit interpretor i traduse n instruciuni main. Avantajul acestei soluii este simplitatea i faptul c, fiind interpretat direct sursa programului, obinem portabilitatea. Dezavantajul este viteza de execuie redus. Probabil cel mai cunoscut limbaj interpretat este limbajul Basic. Compilate: codul surs al programelor este transformat de compilator ntr-un cod ce poate fi executat direct de procesor, numit cod maina. Avantajul este execuia extrem de rapid, dezavantajul fiind lipsa portabilitaii, codul compilat ntr-un format de nivel scazut nu poate fi rulat dect pe platforma de lucru pe care a fost compilat. Limbajul Java combina soluiile amintite mai sus, programele Java fiind att interpretate ct i compilate. Aadar vom avea la dispoziie un compilator responsabil cu transformarea surselor programului n aa numitul cod de octei, precum i un interpretor ce va executa respectivul cod de octei. Codul de octei

Note

Programare orientat obiect este diferit de codul main. Codul main este reprezentat de o succesiune de instruciuni specifice unui anumit procesor i unei anumite platforme de lucru reprezentate n format binar astfel nct s poat fi executate fr a mai necesita nici o prelucrare. Codurile de octei sunt seturi de instruciuni care seamn cu codul scris n limbaj de asamblare i sunt generate de compilator independent de mediul de lucru. n timp ce codul main este executat direct de ctre procesor i poate fi folosit numai pe platforma pe care a fost creat, codul de octei este interpretat de mediul Java i de aceea poate fi rulat pe orice platforma pe care este instalata mediul de execuie Java. Prin maina virtuala Java (JVM) vom nelege mediul de execuie al aplicaiilor Java. Pentru ca un cod de octei s poat fi executat pe un anumit calculator, pe acesta trebuie s fie instalat o main virtual Java. Acest lucru este realizat automat de ctre distribuia J2SDK. 1.2 Primul program Crearea oricrei aplicaii Java presupune efectuarea urmtorilor pai: 1. Scriererea codului surs class FirstApp { public static void main(String args[]) { System.out.println("Hello world!"); } } Toate aplicaiile Java conin o clas principal(primar) n care trebuie s se gaseasc metoda main. Clasele aplicaiei se pot gasi fie ntr-un singur fiier, fie n mai multe. 2. Salvarea fiierelor surs Se va face n fiiere care au obligatoriu extensia java, nici o alt extensie nefiind acceptat. Este recomandat ca fiierul care conine codul surs al clasei primare s aib acelai nume cu cel al clasei, dei acest lucru nu este obligatoriu. S presupunem c am salvat exemplul de mai sus n fiierul C:\intro\FirstApp.java. 3. Compilarea aplicaiei Pentru compilare vom folosi compilatorul javac din distribuia J2SDK. Apelul compilatorului se face pentru fiierul ce conine clasa principala a aplicaiei sau pentru orice fiier/fiiere cu extensia java. Compilatorul creeaza cte un fiier separat pentru fiecare clasa a programului. Acestea au extensia .class i implicit sunt plasate n acelai director cu fiierele sursa. javac FirstApp.java n cazul n care compilarea a reuit va fi generat fiierul FirstApp.class. 4. Rularea aplicaiei Se face cu interpretorul java, apelat pentru unitatea de compilare corespunzatoare clasei principale. Deoarece interpretorul are ca argument de intrare numele clasei principale i nu numele unui fiier, ne vom poziiona n directorul ce conine fiierul FirstApp.class i vom apela interpretorul astfel: java FirstApp Rularea unei aplicaii care nu folosete interfaa grafica, se va face ntr-o fereastra sistem. Note

8 1.3 Structura lexical a limbajului Java

Programare orientat obiect

1.3.1 Setul de caractere


Limbajului Java lucreaz n mod nativ folosind setul de caractere Unicode. Acesta este un standard internaional care nlocuiete vechiul set de caractere ASCII i care folosete pentru reprezentarea caracterelor 2 octei, ceea ce nseamn c 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 fcndu-se prin \uxxxx, unde xxxx reprezint codul caracterului. O alta caracteristic a setului de caractere Unicode este faptul ca ntreg intervalul de reprezentare a simbolurilor este divizat n subintervale numite blocuri, cteva exemple de blocuri fiind: Basic Latin, Greek, Arabic, Gothic,Currency, Mathematical, Arrows, Musical, etc. Mai jos sunt oferite cteva exemple de caractere Unicode. \u0030 - \u0039 : cifre ISO-Latin 0 - 9 \u0660 - \u0669 : cifre arabic-indic 0 - 9 \u03B1 - \u03C9 : simboluri greceti \u2200 - \u22FF : simboluri matematice (,,, etc.) \u4e00 - \u9fff : litere din alfabetul Han (Chinez, Japonez, Coreean) Mai multe informaii legate de reprezentarea Unicode pot fi obinute la adresa http://www.unicode.org.

1.3.2 Cuvinte cheie


Cuvintele rezervate n Java sunt, cu cteva excepii, cele din C++ i au fost enumerate n tabelul de mai jos. Acestea nu pot fi folosite ca nume de clase, interfee, variabile sau metode. true, false, null nu sunt cuvinte cheie, dar nu pot fi nici ele folosite ca nume n aplicaii. Cuvintele marcate prin * sunt rezervate, dar nu sunt folosite. abstract boolean break byte case catch char class const* continue default do double else extends final finally float for goto* if implements import instanceof int interface long native new package private protected public return short static strictfp super switch synchronized this throw throws transient try void volatile while

ncepnd cu versiunea 1.5, mai exist i cuvntul cheie enum.

1.3.3 Identificatori
Sunt secvene nelimitate de litere i cifre Unicode, ncepnd cu o liter. Dup cum am mai spus, identificatorii nu au voie s fie identici cu cuvintele rezervate.

1.3.4 Literali
Note Literalii pot fi de urmtoarele tipuri: ntregi

Programare orientat obiect Sunt acceptate 3 baze de numeraie : baza 10, baza 16 (ncep cu caracterele 0x) i baza 8 (ncep cu cifra 0) i pot fi de dou tipuri: normali - se reprezint pe 4 octei (32 bii) lungi - se reprezint pe 8 octei (64 bii) i se termin cu caracterul L (sau l). Flotani Pentru ca un literal sa fie considerat flotant el trebuie sa aiba cel puin o zecimala dup virgula, sa fie n notaie exponeniala sau sa aiba sufixul F sau f pentru valorile normale - reprezentate pe 32 bii, respectiv D sau d pentru valorile duble - reprezentate pe 64 bii. Exemple: 1.0, 2e2, 3f, 4D. Logici Sunt reprezentai de true - valoarea logic de adevar, respectiv false valoarea logic de fals. Atenie! Spre deosebire de C++, literalii ntregi 1 i 0 nu mai au semnificaia de adevarat, respectiv fals. Caracter Un literal de tip caracter este utilizat pentru a exprima caracterele codului Unicode. Reprezentarea se face fie folosind o liter, fie o secven escape scris ntre apostrofuri. Secvenele escape permit specificarea caracterelor care nu au reprezentare grafic i reprezentarea unor caractere speciale precum backslash, apostrof, etc. Secvenele escape predefinite n Java sunt: \b : Backspace (BS) \t : Tab orizontal (HT) \n : Linie noua (LF) \f : Pagina noua (FF) \r : Inceput de rnd (CR) \" : Ghilimele \ : Apostrof \\ : Backslash iruri de caractere Un literal ir de caractere este format din zero sau mai multe caractere ntre ghilimele. Caracterele care formeaz irul pot fi caractere grafice sau secvene escape. Dac irul este prea lung el poate fi scris ca o concatenare de subiruri de dimensiune mai mica, concatenarea irurilor realizndu-se cu operatorul +, ca n exemplul: "Ana " + " are " + " mere ". irul vid este "". Dup cum vom vedea, orice ir este de fapt o instan a clasei String, definita n pachetul java.lang.

1.3.5 Separatori
Un separator este un caracter care indica sfritul unei unitai lexicale i nceputul alteia. n Java separatorii sunt urmatorii: ( ) [ ] ; , . . Instruciunile unui program se separa cu punct i virgula (;).

1.3.6 Operatori
Operatorii Java sunt, cu mici deosebiri, cei din C++: atribuirea: = operatori matematici: +, -, *, /, %, ++, -- . Este permisa notaia prescurtata de forma lval op= rval: Ex: x += 2; x=x+2; n*= 3;n=n*3; Note

10

Programare orientat obiect Exista operatori pentru autoincrementare i autodecrementare (post i pre): x++, ++x, x=x+1; n--, --n n=n-1; Aceti operatori, dac sunt folosii singuri, au acelai efect n forma post sau prefixat. Diferena dintre aceste dou forme se observ atunci cnd ei sunt folosii n expresii compuse cum ar fi: int x=2, n=5, s; s=(x++)*3; s=(--n)/2; Ordinea n care se vor efectua operaiile n cadrul atribuirilor de mai sus va fi urmtoarea: s=x*3; x++; --n; s=n/2; Astfel, n cazul formei postfixate, variabila este prima dat folosit i apoi modificat, iar n cazul formei prefixate, variabila este prima dat folosit i apoi modificat. n practic trebuie inut cont de acest fapt, pentru a nu aprea erori n calcule. n Java, evaluarea expresiilor logice se face prin metoda scurtcircuitului: evaluarea se oprete n momentul n care valoarea de adevar a expresiei este sigur determinata. operatori logici: &&(and), ||(or), !(not) operatori relaionali: <, <=, >, <=, ==, != operatori pe bii: &(and), |(or), ^ (xor), ~ (not) operatori de translaie: <<, >>, >>> (shift la dreapta fr semn) operatorul if-else: expresie-logica ? val-true : val-false operatorul , (virgula) folosit pentru evaluarea secveniala a operaiilor: int x=0, y=1, z=2; operatorul + pentru concatenarea irurilor: String s1="Ana"; String s2="mere"; int x=10; System.out.println(s1 + " are " + x + " " + s2); operator pentru conversii (cast) : (tip-de-data) sau (clasa) Acest operator este folosit pentru a transforma valori de tip numeric dintr-un tip n altul sau pentru a a schimba tipul unui obiect de la o clas la alta. int a = (int)a; char c = (char)96; int i = 200; long l = (long)i; //conversie n sus (de la int la long) long l2 = (long)200; int i2 = (int)l2; //conversie n jos (de la long la int) n cazul obiectelor, dac se dorete conversia la o clas dintr-un nivel superior al ierarhiei de clase, nu este necesar folosirea operatorului de cast, ci doar cnd se dorete conversia la o clas de pe un nivel inferior al ierarhiei. Exemplu: Fie ierarhia de clase Object-FormaGeometric-Dreptunghi i un obiect obj din clasa FormaGeometric. n acest caz, am putea avea urmtoarele situaii: Object obj=new FormaGeometric(); Dreptunghi obj=(Dreptunghi)new FormaGeometric(); Note

Programare orientat obiect

11

1.3.7 Comentarii
n Java exista trei feluri de comentarii: Comentarii pe mai multe linii, nchise ntre /* i */. Comentarii pe mai multe linii care in de documentaie, nchise ntre /** i */. Textul dintre cele doua secvene este automat mutat n documentaia aplicaiei de ctre generatorul automat de documentaie javadoc. Comentarii pe o singura linie, care incep cu //. Observaii: Nu putem scrie comentarii n interiorul altor comentarii. Nu putem introduce comentarii n interiorul literalilor caracter sau ir de caractere. Secvenele /* i */ pot sa apara pe o linie dup secvena // dar i pierd semnificaia. La fel se ntampla cu secvena // n comentarii care incep cu /* sau */. 1.4 Tipuri de date i variabile

1.4.1 Tipuri de date


n Java tipurile de date se impart n doua categorii: tipuri primitive i tipuri referina. Java pornete de la premiza ca orice este un obiect, prin urmare tipurile de date ar trebui sa fie de fapt definite de clase i toate variabilele ar trebui sa memoreze instane ale acestor clase (obiecte). n principiu acest lucru este adevarat, nsa, pentru usurina programarii, mai exista i aa numitele tipurile primitive de date, care sunt cele uzuale : aritmetice ntregi: byte (1 octet) -2727, short (2) -215215, int (4) -231231, long (8) 263263 reale: float (4 octeti), double (8) caracter: char (2 octei) poate reprezenta 65536 (216) caractere logic: boolean (true i false) n alte limbaje de programare formatul i dimensiunea tipurilor primitive de date pot depinde de platforma pe care ruleaza programul. n Java acest lucru nu mai este valabil, orice dependena de o anumita platforma specific fiind eliminat. Vectorii, clasele i interfeele sunt tipuri referin. Valoarea unei variabile de acest tip este, spre deosebire de tipurile primitive, o referina (adresa de memorie) ctre valoarea sau mulimea de valori reprezentata de variabila respectiva. Exista trei tipuri de date din limbajul C care nu sunt suportate de limbajul Java. Acestea sunt: pointer, struct i union. Pointerii au fost eliminai din cauza ca erau o sursa constanta de erori, locul lor fiind luat de tipul referina, iar struct i union nu i mai au rostul att timp ct tipurile compuse de date sunt formate n Java prin intermediul claselor.

1.4.2 Variabile
Variabilele pot fi de tip primitiv sau referine la obiecte (tip referina). Indiferent de tipul lor, pentru a putea fi folosite variabilele trebuie declarate i, eventual, iniializate. Declararea variabilelor: Tip numeVariabila; Iniializarea variabilelor: Tip numeVariabila = valoare; Declararea constantelor: final Tip numeVariabila; Note

12

Programare orientat obiect Evident, exista posibilitatea de a declara i iniializa mai multe variabile sau constante de acelai tip ntr-o singura instruciune astfel: Tip variabila1[=valoare1], variabila2[=valoare2],...; Observatie: Convenia de numire a variabilelor n Java include, printre altele, urmatoarele criterii: variabilele finale (constante) se scriu cu majuscule; variabilele care nu sunt constante se scriu astfel: prima litera mica iar dac numele variabilei este format din mai muli atomi lexicali, atunci primele litere ale celorlali atomi se scriu cu majuscule. Exemple: final double PI = 3.14; final int MINIM=0, MAXIM = 10; int valoare = 100; char c1=j, c2=a, c3=v, c4=a; long numarElemente = 12345678L; String bauturaMeaPreferata = "apa"; n funcie de locul n care sunt declarate variabilele se mpart n urmtoatele categorii: a. Variabile membre, declarate n interiorul unei clase, vizibile pentru toate metodele clasei respective ct i pentru alte clase n funcie de nivelul lor de acces. b. Parametri metodelor, vizibili doar n metoda respectiva. c. Variabile locale, declarate ntr-o metoda, vizibile doar n metoda respectiva. d. Variabile locale, declarate ntr-un bloc de cod, vizibile doar n blocul respectiv. e. Parametrii de la tratarea excepiilor. Observatii: Variabilele declarate ntr-un for, ramn locale corpului ciclului: for(int i=0; i<100; i++) { //domeniul de vizibilitate al lui i } i = 101;//incorect Nu este permisa ascunderea unei variabile: int x=1; { int x=2; //incorect }

1.4.3 Clase corespunztoare tipurilor de date primitive


Dup cum vzut tipurile Java de date pot fi mprie n primitive i referin. Pentru fiecare tip primitiv exist o clas corespunztoare (wrapper) care permite lucrul orientat obiect cu tipul respectiv. byte Byte short Short int Integer long Long float Float double Double char Character boolean Boolean

Note

Programare orientat obiect

13

Fiecare din aceste clase are un constructor ce permite iniializarea unui obiect avnd o anumit valoare primitiv i metode specializate pentru conversia unui obiect n tipul primitiv corespunztor, de genul tipPrimitivValue: Integer obi = new Integer(1); int i = obi.intValue(); Boolean obb = new Boolean(true); boolean b = obb.booleanValue(); Incepnd cu versiunea 1.5 a limbajului Java, atribuirile explicite ntre tipuri primitve i referin sunt posibile, acest mecanism purtnd numele de autoboxing, respectiv auto-unboxing. Conversia explicit va fi facut de ctre compilator. // Doar de la versiunea 1.5 ! Integer obi = 1; int i = obi; Boolean obb = true; boolean b = obb; 1.5 Controlul execuiei Instruciunile Java pentru controlul execuiei sunt foarte asemanatoare celor din limbajul C i pot fi mparite n urmatoarele categorii: Instruciuni de decizie: if-else, switch-case Instruciuni de salt: for, while, do-while Instruciuni pentru tratarea excepiilor: try-catch-finally, throw Alte instruciuni: break, continue, return, label:

1.5.1 Instruciuni de decizie


1) if-else Se evalueaz valoarea de adevr a unei expresii logice. Dac este adevrat se execut un set de instruciuni i (opional) dac este fals, se execut un alt set de instruciuni. if (expresie-logica) { ... } sau if (expresie-logica) { ... } else { ... } Exemple: if (a>b) a=a-b; if (a<b) a=a+b; else b=b-a; 2) switch-case switch (variabila) { case valoare1:

Note

14

Programare orientat obiect ... break; case valoare2: ... break; ... default: ... } Cu ajutorul acestei instruciuni se testeaz egalitatea valorii unei variabile cu un set finit de valori concrete. n cazul n care este gsit o egalitate, se execut setul de instruciuni corespunztor. Opional, dac nu este gsit o egalitate, se poate trece la executarea setului de instruciuni de pe ramura default care include toate celelalte valori posibile pentru variabila testat, nafar de cele enumerate pe ramurile case. Instruciunea break este necesar la finalul fiecrei ramuri case pentru situaia cnd este gsit o egalitate, s nu se mai testeze ramurile case rmase, ci s se ncheie instruciunea switch. Variabilele care pot fi testate folosind instruciunea switch nu pot fi dect de tipuri primitive. Exemplu: int n=8; switch (n) { case 4: n=n+1; break; case 8: n=n-1; break; case 10: n=n/2; break; default: n=0; } n codul de mai sus, variabila n este comparat pe rnd cu valorile 4, 8, 10. n momentul n care se gsete c n=8, se execut setul de instruciuni corespunzator i instruciunea switch ia sfrit. Dac n nu ar fi fost egal cu niciuna din valorile enumerate, s-ar fi trecut la executarea setului de instruciuni de pe ramura default.

1.5.2 Instruciuni de salt


Aceste instruciuni se mai numesc i repetitive deoarece permit repetarea unui set de instruciuni de mai multe ori. 3) for for(initializare; expresie-logica; pas-iteratie) { //Corpul buclei //Set de instructiuni } Aceast instruciune folosete n cele mai uzuale cazuri o variabil numit contor care la nceput este initializat cu o anumit valoare dup care se trece la repetarea urmtorilor pai: se testeaz expresia logic, numit i condiie de continuare dac este adevrat, se execut o dat corpul buclei (set de instruciuni) se modific contorul conform pas-iteraie se trece din nou la evaluarea expresiei logice. Astfel, atta timp ct expresia logic rmne adevrat, se va repeta executarea corpului buclei. Exemplu: int i, n=1;

Note

Programare orientat obiect for (i=1; i<=5; i++) n=n*2; Att la iniializare ct i n pasul de iteraie pot fi mai multe instruciuni desparite prin virgula. for(int i=0, j=100; i < 100 && j > 0; i++, j--) { ... } ncepnd cu varianta 1.5, Java a introdus o nou form a instruciunii for, special creat pentru a putea parcurge tablouri i colecii. Aceast form a instruciunii se mai numete i foreach. Noutatea const c n faptul nu mai este necesar un contor pentru a parcurge o secven de elemente, ci este nevoie doar de o variabil care s aib acelai tip cu elementele din secvena de parcurs. Exemplu: float f[] = new float[10]; for(float x : f) System.out.println(x); 4) while while (expresie-logica) { //Set de instructiuni } Atta timp ct o expresie logic este adevrat, se repet executarea unui set de instruciuni. Exemplu: int n=5, s=0; while (n>0) { s=s+n; n--; } 5) do-while do { //Set de instructiuni } while (expresie-logica); Se repet executarea unui set de instruciuni, atta timp ct o expresie logic este adevrat. Diferena fa de instruciunea while const n faptul c expresia logic este testat dup executarea setului de instruciuni, astfel c, dac ea este fals de la nceput, n cazul instruciunii do-while el va fi totui executat o dat, ceea ce nu se va ntmpla la instruciunea while. Observaie: Instruciunea for poate fi scris ca i o instruciune while echivalent: for(initializare; expresie-logica; pas-iteratie) { //Set de instructiuni } poate fi scris ca i: initializare while (expresie-logica) { //Set de instructiuni pas-iteratie }

15

Note

16

Programare orientat obiect

1.5.3 Instruciuni pentru tratarea excepiilor


Instruciunile pentru tratarea excepiilor sunt try-catch-finally, respectiv throw i vor fi tratate n capitolul Excepii.

1.5.4 Alte instruciuni


break: parasete forat corpul unei structuri repetitive. continue: termina forat iteraia curenta a unui ciclu i trece la urmatoarea iteraie. return [valoare]: termina o metoda i, eventual, returneaza o valorare. numeEticheta: : definete o eticheta. Dei n Java nu exist goto, se pot defini totui etichete folosite n expresii de genul: break numeEticheata sau continue numeEticheta, utile pentru a controla punctul de ieire dintr-o structur repetitiv, ca n exemplul de mai jos: i=0; eticheta: while (i < 10) { System.out.println("i="+i); j=0; while (j < 10) { j++; if (j==5) continue eticheta; if (j==7) break eticheta; System.out.println("j="+j); } i++; } 1.6 Tipuri enumerate (enum) O noutate introdus cu varianta 1.5 este posibilitatea declarrii unor enumerri de elemente, facilitate existent n alte limbaje cum ar fi C i C++, ns care nu a existat de la nceput implementat n Java. Exemplu: public enum Zile_lucr { LUNI, MARTI, MIERCURI, JOI, VINERI } Prin convenie, deoarece elementele unei enumerri sunt constante, ele vor fi scrise cu majuscule. Cteva elemente care sunt implementate implicit pentru o enumerare sunt: metoda toString() care permite afiare unei valori din enumerare ca i ir de caractere metoda ordinal() care permite aflarea numrului de ordine a unei valori din enumerare (numerele de ordine ncep de la 0) metoda static values() care va genera un tablou cu elementele enumerrii Exemplu: public class ZileDeMunca { public static void main(String[] args) { for (Zile_lucr z : Zile_lucr.values() System.out.println (z + a + z.ordinal() + -a zi);

Note

Programare orientat obiect } } La rulare se va afisa: LUNI a 0-a zi MARTI a 1-a zi MIERCURI a 2-a zi JOI a 3-a zi VINERI a 4-a zi Un avantaj suplimetar oferit de tipul enumerat este faptul c va permite testarea valorilor de tip ir de caractere ntr-o instruciune switch, ceea ce altfel nu era posibil. Exemplu: Zile_lucr z; switch (z) { case LUNI: } 1.7 Folosirea argumentelor de la linia de comand

17

1.7.1 Transmiterea argumentelor


O aplicaie Java poate primi oricte argumente de la linia de comanda n momentul lansrii ei. Aceste argumente sunt utile pentru a permite utilizatorului s specifice diverse opiuni legate de funcionarea aplicaiei sau s furnizeze anumite date iniiale programului. Argumentele de la linia de comand sunt introduse la lansarea unei aplicaii, fiind specificate dup numele aplicaiei i separate prin spaiu. Formatul general pentru lansarea unei aplicaii care primete argumente de la linia de comand este: java NumeAplicatie [arg0 arg1 . . . argn] n cazul n care sunt mai multe, argumentele trebuie separate prin spaii, iar dac unul dintre argumente conine spaii, atunci el trebuie pus ntre ghilimele. Evident, o aplicaie poate s nu primeasc nici un argument sau poate s ignore argumentele primite de la linia de comand.

1.7.2 Primirea argumentelor


n momentul lansrii unei aplicaii interpretorul parcurge linia de comand cu care a fost lansat aplicatia i, n cazul n care exist, transmite programului argumentele specificate sub forma unui vector de iruri. Acesta este primit de aplicaie ca parametru al metodei main. Reamintim c formatul metodei main din clasa principal este: public static void main (String args[]) Vectorul args primit ca parametru de metoda main va conine toate argumentele transmise programului de la linia de comand. Vectorul args este instaniat cu un numr de elemente egal cu numrul argumentelor primite de la linia de comand. Aadar, pentru a afla numrul de argumente primite de program este suficient s aflm dimensiunea vectorului args prin intermediul atributului length: public static void main (String args[]) { int numarArgumente = args.length ; } n cazul n care aplicaia presupune existena unor argumente de la linia de comand, ns acestea nu au fost transmise programului la lansarea sa, vor

Note

18

Programare orientat obiect aprea excepii (erori) de tipul ArrayIndexOutOfBoundsException. Tratarea acestor excepii este prezentat n capitolul Excepii. Din acest motiv, este necesar s testm dac programul a primit argumentele de la linia de comand necesare pentru funcionarea sa i, n caz contrar, s afieze un mesaj de avertizare sau s foloseasc nite valori implicite, ca n exemplul de mai jos: public class Salut { public static void main (String args[]) { if (args.length == 0) { System.out.println("Numar insuficient de argumente!"); System.exit(-1); //termina aplicatia } String nume = args[0]; //exista sigur String prenume; if (args.length >= 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 conine pe prima poziie numele aplicaiei, ntruct n Java numele aplicaiei este chiar numele clasei principale, adic a clasei n care se gasete metoda main(). S consider n continuare un exemplu simplu n care se dorete afiarea pe ecran a argumentelor primite de la linia de comand: public class Afisare { public static void main (String[] args) { for (int i = 0; i < args.length; i++) System.out.println(args[i]); } } Un apel de genul: java Afisare Hello Java va produce urmtorul rezultat (aplicaia a primit 2 argumente): Hello Java Apelul: java Afisare "Hello Java" va produce ns alt rezultat (aplicaia a primit un singur argument): Hello Java

1.7.3 Argumente numerice


Argumentele de la linia de comand sunt primite sub forma unui vector de iruri (obiecte de tip String). n cazul n care unele dintre acestea reprezint valori numerice ele vor trebui convertite din iruri n numere. Acest lucru se realizeaz cu metode de tipul parseTipNumeric aflate n clasa corespunzatoare tipului n care vrem s facem conversia: Integer, Float, Double, etc. S considerm, de exemplu, c aplicaia Power ridic un numar real la o putere ntreag, argumentele fiind trimise de la linia de comand sub forma: java Power "1.5" "2" //ridica 1.5 la puterea 2 Conversia celor dou argumente n numere se va face astfel:

Note

Programare orientat obiect 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=" + Math.pow(numar, putere)); } } Metodele de tipul parseTipNumeric() pot produce excepii (erori) de tipul NumberFormatException n cazul n care irul primit ca parametru nu reprezint un numar de tipul respectiv. Tratarea acestor excepii este prezentat n capitolul Excepii.

19

Test de autoevaluare: 1. Care sunt principiile de baz ale programrii orientate obiect?

2.

Care sunt caracterele valide cu care poate ncepe numele unei variabile n Java?

3.

Numii trei tipuri de date primitive din Java.

4.

Care sunt cele trei instruciuni de control repetitive?

5.

Ce tip implicit au datele transmise din linia de comanda?

Bibliografie : 1. Cristian Frsinaru Curs practic de Java 2. Bruce Eckel Thinking in Java 4th Edition, Ed. Prentice Hall, 2006, ISBN 0-13-187248-6 3. P. Niemeyer, J. Knudsen - Learning Java 3rd Edition, Ed. OReilly, 2005 4. .Tanas,.Andrei,C. Olaru Java de la 0 la expert, Ed.Polirom, 2007, ISBN 978-973-46-0317-6 5. D.Danciu, G.Mardale - Arta programrii n JAVA (Vol. I) Elemente-suport fundamentale, Ed. Albastr, 2005

Note

20

Programare orientat obiect

Note

Programare orientat obiect II. Elemente de baz ale programarii orientate obiect baz

21

2.1 Clase i obiecte

Obiective: Cunoaterea conceptului fundamental de clas terea clas Cunoaterea elementelor de baz care compun o clas terea baz Cunoaterea modificatorilor de acces de la diferite nivele terea (clas, atribut, metod , metod) nelegerea diferen dintre membrii de clas (statici) i cei de elegerea diferenei instan Declararea, ini iniializarea i utilizarea tablourilor Declararea, ini iniializarea i utilizarea irurilor de caractere Clasa este un concept de baz al programrii orientate obiect, domeniu n baz rii care reprezint structura care define te caracteristicile abstracte ale unui lucru definete (obiect), printre care caracteristicile acestuia (atributele sale, cmpuri sau proprieti), precum i comportamentele acestui lucru (lucrurile pe care le poate omportamentele face, sau metode, operaii sau propriet ii proprieti). Se poate spune c o clas este schia care descrie natura unui lucru. De clas a exemplu, clasa Cine va conine caracteristicile tuturor cinilor, precum ras sau ine ras culoarea prului (caracteristici), precum i capacitatea de a ltra i de a sta rului (comportament). Clasele asigur modularitatea i structura ntr-un program de calculator un orientat pe obiecte. O clas ar trebui s poat fi neleas de ctre o persoan care s tre nu tie programare dar cunosc toare a domeniului problemei, caracteristicile tie cunosctoare clasei ar trebui s aib sens n respectivul context. De asemenea, codul clasei ar trebui s fie auto-suficient (folosind n general ncapsularea). suficient n ansamblul lor, propriet proprietile i metodele definite printr-o clas sunt o numite membri. Pentru a da consisten atributelor este nevoie de cearea unui obiect ntr ntr-o clas. Astfel, un obiect se mai nume i instan a unei clase. . numete ncapsularea este termenul care define accesul la membrii unei clase. definete Un atribut sau o metod a unui obiect pot sau nu s fie accesate de ctre un obiect s tre exterior clasei. Se poate ntmpla ca o parte din membrii unei clase s poat fi s poat utilizai doar n interiorul clasei i s nu se permit accesul la ei dinafar Ca i dinafar. urmare, se spune c acetia vor fi ncapsula n interiorul clasei, fr a fi vizibili tia ncapsulai sau accesabili din exterior. Definirea accesului la un membru al unei clase se face prin intermediul specificatorilor de acces acces. 2.1.1 Crearea claselor a) Declararea claselor Clasele reprezint o modalitate de a introduce noi tipuri de date ntr ntr-o aplicaie Java, cealalt modalitate fiind prin intermediul interfe elor. Declararea interfeelor. unei clase respect urmtorul format general: torul [modificatori clasa] clasa]class NumeClasa [extends NumeSuperclasa] [implements Interfata1 [, Interfata2 ... ]]

Note

22

Programare orientat obiect { // Corpul clasei } Aadar, prima parte a declaraiei o ocup modificatorii clasei. Acetia sunt: public: Implicit, o clas poate fi folosit doar de clasele aflate n acelai pachet (librrie) cu clasa respectiv (dac nu se specific un anume pachet, toate clasele din directorul curent sunt considerate a fi n acelai pachet). O clas declarat cu public poate fi folosit din orice alt clas, indiferent de pachetul n care se gsete. abstract : Declar o clas abstract (ablon). O clas abstract nu poate fi instaniat, fiind folosit doar pentru a crea un model comun pentru o serie de subclase. final : Declar c respectiva clas nu poate avea subclase. Declarare claselor finale are dou scopuri: securitate: unele metode pot atepta ca parametru un obiect al unei anumite clase i nu al unei subclase, dar tipul exact al unui obiect nu poate fi aflat cu exactitate decat n momentul executiei; n felul acesta nu s-ar mai putea realiza obiectivul limbajului Java ca un program care a trecut compilarea s nu mai fie susceptibil de nici o eroare. programare n spririt orientat-obiect: O clasa perfect nu trebuie s mai aib subclase. Dup numele clasei putem specifica, dac este cazul, faptul c respectiva clas este subclas a unei alte clase cu numele NumeSuperclasa sau/i c implementeaz una sau mai multe interfee, ale cror nume trebuie separate prin virgul. b) Extinderea claselor Spre deosebire de alte limbaje de programare orientate-obiect, Java permite doar motenirea simpl, ceea ce nseamn c o clas poate avea un singur printe (superclas). Pe de alta parte, o clas poate avea oricti motenitori (subclase), de unde rezult c mulimea tuturor claselor definite n Java poate fi vazut ca un arbore, rdcina acestuia fiind clasa Object. Aadar, Object este singura clas care nu are printe, fiind foarte important n modul de lucru cu obiecte si structuri de date n Java. Extinderea unei clase se realizeaz folosind cuvntul cheie extends: class B extends A {...} // A este superclasa clasei B // B este o subclasa a clasei A O subclas motenete de la printele su toate atributele i metodele care nu sunt private. Pe lng acestea, clasa derivat poate aduga noi atribute i metode. Prin motenire, o clas poate fi reutilizat pentru a modela o alta clas, care va fi o subclas a sa (clas derivat). c) Corpul unei clase Corpul unei clase urmeaz imediat dup declararea clasei i este cuprins ntre acolade. Coninutul acestuia este format din: Declararea i, eventual, iniializarea variabilelor de instan i de clas (cunoscute mpreun ca variabile membre). Declararea i implementarea constructorilor. Declararea i implementarea metodelor de instana i de clas (cunoscute mpreun ca metode membre).

Note

Programare orientat obiect Declararea unor clase imbricate (interne). d) Constructorii unei clase Constructorii unei clase sunt metode speciale care au acelai nume cu cel al clasei, nu returneaz nici o valoare i sunt folosii pentru iniializarea obiectelor acelei clase n momentul instanierii lor. Constructorii nu sunt considerai ca fiind membrii ai clasei. class NumeClasa { [modificatori] NumeClasa([argumente]) { // Constructor } } O clas poate avea unul sau mai muli constructori care trebuie ns s difere prin lista de argumente primite. n felul acesta sunt permise diverse tipuri de iniializri ale obiectelor la crearea lor, n funcie de numrul parametrilor cu care este apelat constructorul. S considerm ca exemplu declararea unei clase care descrie noiunea de dreptunghi i trei posibili constructori pentru aceasta clas: class Dreptunghi { double x, y, w, h; Dreptunghi(double x1, double y1, double w1, double h1) { // Cel mai general constructor x=x1; y=y1; w=w1; h=h1; System.out.println("Instantiere dreptunghi"); } Dreptunghi(double w1, double h1) { // Constructor cu doua argumente x=0; y=0; w=w1; h=h1; System.out.println("Instantiere dreptunghi"); } Dreptunghi() { // Constructor fr argumente x=0; y=0; w=0; h=0; System.out.println("Instantiere dreptunghi"); } } Constructorii sunt apelai automat la instanierea unui obiect. n cazul n care dorim s apelm explicit constructorul unei clase folosim expresia this(argumente), care apeleaz constructorul corespunztor (ca argumente) al clasei respective. Aceast metod este folosit atunci cnd sunt implementai mai muli constructori pentru o clas, pentru a nu repeta secvenele de cod scrise deja la constructorii cu mai multe argumente (mai generali). Mai eficient, fr a repeta aceleai secvene de cod n toi constructorii (cum ar fi afiarea mesajului Instantiere dreptunghi), clasa de mai sus poate fi rescris astfel: class Dreptunghi { double x, y, w, h; Dreptunghi(double x1, double y1, double w1, double h1) { x=x1; y=y1; w=w1; h=h1; System.out.println("Instantiere dreptunghi"); }

23

Note

24 Dreptunghi(double w1, double h1) { this(0, 0, w1, h1); // Apelam constructorul cu 4 argumente } Dreptunghi() { this(0, 0); // Apelam constructorul cu 2 argumente }

Programare orientat obiect

} Atenie! Apelul explicit al unui constructor nu poate aprea dect ntr-un alt constructor si trebuie s fie prima instruciune din constructorul respectiv. Constructorul implicit: Constructorii sunt apelai automat la instanierea unui obiect. n cazul n care scriem o clas care nu are declarat nici un constructor, sistemul i creeaz automat un constructor implicit, care nu primete nici un argument i care nu face nimic. Deci prezena constructorilor n corpul unei clase un este obligatorie. Dac ns scriem un constructor pentru o clas, care are mai mult de un argument, atunci constructorul implicit (fr nici un argument) nu va mai fi furnizat implicit de ctre sistem. Constructorii unei clase pot avea urmtorii modificatori de acces: public: n orice alt clas se pot crea instane ale clasei respective. protected: Doar n subclase pot fi create obiecte de tipul clasei respective. private: n nici o alt clas nu se pot instania obiecte ale acestei clase. O astfel de clas poate conine metode publice (numite factory methods) care s fie responsabile cu crearea obiectelor, controlnd n felul acesta diverse aspecte legate de instanierea clasei respective. implicit: Doar n clasele din acelai pachet se pot crea instane ale clasei respective. e) Declararea variabilelor Variabilele membre ale unei clase se declar de obicei naintea metodelor, dei acest lucru nu este impus de ctre compilator. Variabilele membre ale unei clase se declar n corpul clasei i nu n corpul unei metode, fiind vizibile n toate metodele respectivei clase. Variabilele declarate n cadrul unei metode sunt locale metodei respective. Declararea unei variabile presupune specificarea urmtoarelor lucruri: numele variabilei tipul de date al acesteia nivelul de acces la acea variabila din alte clase dac este constant sau nu dac este variabil de instan sau de clas ali modificatori Generic, o variabil se declar astfel: [modificatori] TipDate numeVariabila [ = valoareInitiala ]; unde un modificator poate fi : un modificator de acces : public, protected, private unul din cuvintele rezervate: static, final, transient, volatile Exemple de declaraii de variabile membre: class Exemplu { double x; protected static int n; public String s = "abcd";

Note

Programare orientat obiect private Point p = new Point(10, 10); final static long MAX = 100000L; } S analizm modificatorii care pot fi specificai pentru o variabil: static: Prezena lui declar c o variabil este variabil de clas i nu de instan. Astfel, se va aloca o singur dat memorie pentru ea i apelul ei se va face prin intermediul clasei i nu printr-un obiect al clasei (instan). int variabilaInstanta; static int variabilaClasa; final: Indic faptul c valoarea variabilei nu mai poate fi schimbat, cu alte cuvinte este folosit pentru declararea constantelor. final double PI = 3.14 ; ... PI = 3.141; // Eroare la compilare ! Prin convenie, numele variabilelor finale se scriu cu litere mari. Folosirea lui final aduce o flexibilitate sporit n lucrul cu constante, n sensul c valoarea unei variabile nu trebuie specificat neaprat la declararea ei (ca n exemplul de mai sus), ci poate fi specificat i ulterior ntr-un constructor, dup care ea nu va mai putea fi modificat. 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 particip la serializare. volatile: Este folosit pentru a semnala compilatorului s nu execute anumite optimizri asupra membrilor unei clase. Este o facilitate avansat a limbajului Java. f) this i super Sunt variabile predefinite care fac referina, n cadrul unui obiect, la obiectul propriu-zis (this), respectiv la instana printelui (super). Sunt folosite n general pentru a rezolva conflicte de nume prin referirea explicit a unei variabile sau metode membre. Utilizate sub form de metode, au rolul de a apela constructorii corespunztori ca argumente ai clasei curente, respectiv ai superclasei. g) Implementarea metodelor Declararea metodelor Metodele sunt responsabile cu descrierea comportamentului unui obiect. Intruct Java este un limbaj de programare complet orientat-obiect, metodele se pot gsi doar n cadrul claselor. Generic, o metod se declar astfel: [modificatori] tipReturnat numeMetoda ( [argumente] ) [throws TipExceptie1, TipExceptie2, ...] { // Corpul metodei }

25

Note

26

Programare orientat obiect unde un modificator poate fi : un specificator de acces : public, protected, private unul din cuvintele rezervate: static, abstract, final, native, synchronized S analizm modificatorii care pot fi specificai pentru o metod: static: Prezena lui declar c o metod este de clas i nu de instan. n cazul acesta, apelul metodei se va face prin intermediul clasei i nu printr-un obiect al clasei (instan). n general, n cadrul metodelor statice se vor folosi atribute statice. abstract: Permite declararea metodelor abstracte. O metod abstract este o metod care nu are implementare i trebuie obligatoriu s fac parte dintr-o clas abstract. final: Specific faptul c acea metoda nu mai poate fi supradefinit n subclasele clasei n care ea este definit ca fiind final. Acest lucru este util dac respectiva metod are o implementare care nu trebuie schimbat sub nici o form n subclasele ei, fiind critic pentru consistena strii unui obiect. native: n cazul n care avem o librrie important de funcii scrise n alt limbaj de programare, cum ar fi C, C++ i limbajul de asamblare, acestea pot fi refolosite din programele Java. Tehnologia care permite acest lucru se numete JNI (Java Native Interface) i permite asocierea dintre metode Java declarate cu native i metode native scrise n limbajele de programare menionate. synchronized: Este folosit n cazul n care se lucreaz cu mai multe fire de execuie iar metoda respectiv gestioneaz resurse comune. Are ca efect construirea unui monitor care nu permite executarea metodei, la un moment dat, dect unui singur fir de execuie. Tipul returnat de o metod Metodele pot sau nu s returneze o valoare la terminarea lor. Tipul returnat poate fi att un tip primitiv de date sau o referin la un obiect al unei clase. n cazul n care o metod nu returneaz nimic atunci trebuie obligatoriu specificat cuvntul cheie void ca tip returnat. Dac o metod trebuie s returneze o valoare acest lucru se realizeaz prin intermediul instruciunii return, care trebuie s apar n toate situaiile de terminare a funciei. Exemplu: double radical(double x) { if (x >= 0) return Math.sqrt(x); else { System.out.println("Argument negativ !"); // Eroare la compilare // Lipseste return pe aceasta ramura } } n cazul n care n declaraia funciei, tipul returnat este un tip primitiv de date, valoarea returnat la terminarea funciei trebuie s aib obligatoriu acel tip sau un subtip al su, altfel va fi furnizat o eroare la compilare. Dac valoarea returnat este o referin la un obiect al unei clase, atunci clasa obiectului returnat trebuie s coincid sau s fie o subclas a clasei specificate la declararea metodei. De exemplu, fie clasa Poligon i subclasa acesteia Patrat. Poligon metoda1( ) { Poligon p = new Poligon();

Note

Programare orientat obiect 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 } Trimiterea parametrilor ctre o metod Signatura unei metode este dat de numarul i tipul argumentelor primite de acea metod. Tipul de date al unui argument poate fi orice tip valid al limbajului Java, att tip primitiv ct i tip referin. tipReturnat metoda([Tip1 arg1, Tip2 arg2, ...]) Exemplu: void adaugarePersoana(String nume, int varsta, float salariu) // String este tip referinta // int si float sunt tipuri primitive Spre deosebire de alte limbaje, n Java nu pot fi trimise ca parametri ai unei metode referine la alte metode (funcii), ns pot fi trimise referine la obiecte care s conin implementarea acelor metode, pentru a fi apelate. Pn la apariia versiunii 1.5, n Java o metod nu putea primi un numr variabil de argumente, ceea ce nseamna c apelul unei metode trebuia s se fac cu specificarea exact a numarului i tipurilor argumentelor. Numele argumentelor primite trebuie s difere ntre ele i nu trebuie s coincid cu numele nici uneia din variabilele locale ale metodei. Pot ns s coincid cu numele variabilelor membre ale clasei, caz n care diferenierea 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; } } n Java argumentele sunt trimise doar prin valoare (pass-by-value). Acest lucru nseamn c metoda recepioneaz doar valorile variabilelor primite ca parametri. Cnd argumentul are tip primitiv de date, metoda nu-i poate schimba valoarea dect local (n cadrul metodei); la revenirea din metod variabila are aceeai valoare ca naintea apelului, modificrile fcute n cadrul metodei fiind pierdute. Note

27

28

Programare orientat obiect Cnd argumentul este de tip referin, metoda nu poate schimba valoarea referinei obiectului, ns poate apela metodele acelui obiect i poate modifica orice variabil membr accesibil. Aadar, dac dorim ca o metod s schimbe starea (valoarea) unui argument primit, atunci el trebuie s fie neaparat de tip referin. 2.1.2 Clase imbricate a) Definirea claselor imbricate O clas imbricat este, prin definiie, o clas membr a unei alte clase, numit i clas de acoperire. n funcie de situaie, definirea unei clase interne se poate face fie ca membru al clasei de acoperire - caz n care este accesibil tuturor metodelor, fie local n cadrul unei metode. class ClasaDeAcoperire{ class ClasaImbricata1 { // Clasa membru } void metoda() { class ClasaImbricata2 { // Clasa locala metodei } } } Folosirea claselor imbricate se face atunci cnd o clas are nevoie n implementarea ei de o alt clas i nu exist nici un motiv pentru care aceasta din urm s fie declarat de sine stttoare (nu mai este folosit nicieri). O clas imbricat are un privilegiu special fa de celelalte clase i anume acces nerestricionat la toate variabilele clasei de acoperire, chiar dac acestea sunt private. O clas declarat local unei metode va avea acces i la variabilele finale declarate n metoda respectiv. class ClasaDeAcoperire{ private int x=1; class ClasaImbricata1 { int a=x; } void metoda() { final int y=2; int z=3; class ClasaImbricata2 { int b=x; int c=y; int d=z; // Incorect } } } O clas imbricat membr (care nu este local unei metode) poate fi referit din exteriorul clasei de acoperire folosind expresia: ClasaDeAcoperire.ClasaImbricata Clasele membru pot fi declarate cu modificatorii public, protected, private pentru a controla nivelul lor de acces din exterior, ntocmai ca orice variabil sau metod membr a clasei. Pentru clasele imbricate locale unei metode nu sunt permii acesti modificatori. Toate clasele imbricate pot fi

Note

Programare orientat obiect declarate folosind modificatorii abstract i final, semnificaia lor fiind aceeai ca i n cazul claselor obinuite. b) Clase interne Spre deosebire de clasele obinuite, o clas imbricat poate fi declarat static sau nu. O clas imbricat nestatic se numete clasa intern. class ClasaDeAcoperire{ ... class ClasaInterna { ... } static class ClasaImbricataStatica { ... } } Diferenierea acestor denumiri se face deoarece: o clas imbricat reflect relaia sintactic a dou clase: codul unei clase apare n interiorul codului altei clase; o clas intern reflect relaia dintre instanele a dou clase, n sensul c o instana a unei clase interne nu poate exista decat n cadrul unei instane a clasei de acoperire. n general, cele mai folosite clase imbricate sunt cele interne. Aadar, o clas intern este o clas imbricat ale carei instane nu pot exista dect n cadrul instanelor clasei de acoperire i care are acces direct la toi membrii clasei sale de acoperire. c) Identificare claselor imbricate Dup cum tim orice clas produce la compilare aa numitele uniti de compilare, care sunt fiiere avnd numele clasei respective i extensia .class i care conin toate informaiile despre clasa respectiv. Pentru clasele imbricate aceste uniti de compilare sunt denumite astfel: numele clasei de acoperire, urmat de simbolul $ apoi de numele clasei imbricate. class ClasaDeAcoperire{ class ClasaInterna1 {} class ClasaInterna2 {} } Pentru exemplul de mai sus vor fi generate trei fiiere: ClasaDeAcoperire.class ClasaDeAcoperire$ClasaInterna1.class ClasaDeAcoperire$ClasaInterna2.class n cazul n care clasele imbricate au la rndul lor alte clase imbricate (situaie mai puin uzual) denumirea lor se face dup aceeai regul: adugarea unui $ i apoi numele clasei imbricate. d) Clase anonime Exist posibilitatea definirii unor clase imbricate locale, fr nume, utilizate doar pentru instanierea unui obiect de un anumit tip. Astfel de clase se numesc clase anonime i sunt foarte utile n situaii cum ar fi crearea unor obiecte ce implementeaz o anumit interfa sau extind o anumit clas abstract. Fiierele rezultate n urma compilrii claselor anonime vor avea numele de forma ClasaAcoperire.$1,..., ClasaAcoperire.$n

29

Note

30

Programare orientat obiect unde n este numrul de clase anonime definite n clasa respectiv de acoperire. 2.1.3 Crearea obiectelor a) Etape n Java, ca n orice limbaj de programare orientat-obiect, crearea obiectelor se realizeaz prin instanierea unei clase i implic urmtoarele lucruri: Declararea: Presupune specificarea tipului acelui obiect, cu alte cuvinte specificarea clasei acestuia (vom vedea c tipul unui obiect poate fi i o interfa). NumeClasa numeObiect; Instanierea: Se realizeaz prin intermediul operatorului new i are ca efect crearea efectiv a obiectului cu alocarea spaiului de memorie corespunztor. numeObiect = new NumeClasa(); Iniializarea: Se realizeaz prin intermediul constructorilor clasei respective. Iniializarea este de fapt parte integrant a procesului de instaniere, n sensul c imediat dup alocarea memoriei ca efect al operatorului new este apelat constructorul specificat. Parantezele rotunde de dup numele clasei indic faptul c acolo este de fapt un apel la unul din constructorii clasei i nu simpla specificare a numelui clasei. Pentru simplificarea scrierii, uzual, cei 3 pai se mai sus sunt adesea folosii mpreun: NumeClasa numeObiect = new NumeClasa([argumente constructor]); Fie clasa Rectangle o clas ce descrie suprafee grafice rectangulare, definite de coordonatele colului stnga sus (originea) i limea, respectiv nlimea i s presupunem c clasa Rectangle are urmtorii constructori: public Rectangle() public Rectangle(int origineX, int origineY, int latime, int inaltime) S considerm exemplul n care declarm i instaniem trei obiecte din clasa Rectangle: Rectangle r1, r2; r1 = new Rectangle(); r2 = new Rectangle(0, 0, 100, 200); Rectangle r3= new Rectangle(0, 0, 150, 150); n primul caz Rectangle() este un apel ctre constructorul clasei Rectangle care este responsabil cu iniializarea obiectului cu valorile implicite. n al doilea caz, iniializarea se poate face i cu anumii parametri, cu condiia s existe un constructor al clasei respective care s accepte parametrii respectivi. Pentru cel de-al treilea obiect, declararea, instanierea i iniializarea au fost fcute ntr-un singur pas. b) Folosirea obiectelor Odat un obiect creat, el poate fi folosit n urmtoarele sensuri: aflarea unor informaii despre obiect, schimbarea strii sale sau executarea unor aciuni. 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 exemplu clasa Rectangle are variabilele publice x, y, width, height. Aflarea valorilor acestor variabile sau schimbarea lor se face prin construcii de genul:

Note

Programare orientat obiect Rectangle patrat = new Rectangle(0, 0, 100, 100); System.out.println(patrat.width); //afiseaza 100 patrat.x = 10; patrat.y = 20; //schimba originea Accesul la variabilele unui obiect se face n conformitate cu drepturile de acces pe care le ofer variabilele respective celorlalte clase. Apelul unei metode se face prin: obiect.metoda([parametri]) Exemplu: Rectangle patrat = new Rectangle(0, 0, 100, 200); patrat.setLocation(10, 20); //schimba originea patrat.setSize(200, 300); //schimba dimensiunea Se observ c valorile variabilelor pot fi modificate indirect prin intermediul metodelor sale. Programarea orientat obiect descurajeaz folosirea direct a variabilelor unui obiect deoarece acesta poate fi adus n stri inconsistente (ireale). n schimb, pentru fiecare variabil care descrie starea obiectului trebuie s existe metode care s permit schimbarea/aflarea valorilor variabilelor sale. Acestea se numesc metode de accesare, sau metode setter - getter i au numele de forma setVariabila, respectiv getVariabila. Exemplu: patrat.width = -100; //stare inconsistenta patrat.setSize(-100, -200); //metoda setter //metoda setSize poate sa testeze dac noile valori sunt corecte si sa valideze sau nu schimbarea lor c) Distrugerea obiectelor Multe limbaje de programare impun ca programatorul s in evidena obiectelor create i s le distrug n mod explicit atunci cnd nu mai este nevoie de ele, cu alte cuvinte s administreze singur memoria ocupat de obiectele sale. Practica a demonstrat c aceast tehnic este una din principalele furnizoare de erori ce duc la funcionarea defectuoas a programelor. n Java programatorul nu mai are responsabilitatea distrugerii obiectelor sale ntruct, n momentul rulrii unui program, simultan cu interpretorul Java, ruleaz i un proces care se ocup cu distrugerea obiectelor care nu mai sunt folosite. Acest proces pus la dispoziie de platforma Java de lucru se numete garbage collector (colector de gunoi), prescurtat gc. Un obiect este eliminat din memorie de procesul de colectare atunci cnd nu mai exist nici o referin la acesta. Referinele (care sunt de fapt variabile) sunt distruse dou moduri: natural, atunci cnd variabila respectiv iese din domeniul su de vizibilitate, de exemplu la terminarea metodei n care ea a fost declarat; explicit, dac atribuim variabilei respective valoare null. Cum funcioneaz garbage collector? Garbage collector este un proces de prioritate scazut care se execut periodic, scaneaz dinamic memoria ocupat de programul Java aflat n execuie i marcheaz acele obiecte care au referine directe sau indirecte. Dup ce toate obiectele au fost parcurse, cele care au rmas nemarcate sunt eliminate automat din memorie. Apelul metodei gc din clasa System sugereaz mainii virtuale Java s depun eforturi n recuperarea memoriei ocupate de obiecte care nu mai sunt folosite, fr a fora ns pornirea procesului. Note

31

32

Programare orientat obiect Inainte ca un obiect s fie eliminat din memorie, procesul gc d acelui obiect posibilitatea s curee dup el, apelnd metoda de finalizare a obiectului respectiv. Uzual, n timpul finalizrii un obiect i inchide fisierele i socket-urile folosite, distruge referinele ctre alte obiecte (pentru a usura sarcina colectorului de gunoaie), etc. Codul pentru finalizarea unui obiect trebuie scris ntr-o metod special numit finalize a clasei ce descrie obiectul respectiv. 2.1.4 Membri de instan i membri de clas O clas Java poate conine dou tipuri de variabile i metode : de instan: declarate fr modificatorul static, specifice fiecrei instane create dintr-o clas i de clas: declarate cu modificatorul static, specifice clasei. a) Variabile de instan i de clas Cnd declarm o variabil membr fr modificatorul static, cum ar fi variabila x n exemplul de mai jos: class Exemplu1 { int x ; //variabila de instanta } se declar de fapt o variabil de instan, ceea ce nseamn c la fiecare creare a unui obiect al clasei Exemplu1 sistemul aloc o zon de memorie separat pentru memorarea valorii lui x. Exemplu1 o1 = new Exemplu1(); o1.x = 100; Exemplu1 o2 = new Exemplu1(); o2.x = 200; System.out.println(o1.x); // Afiseaza 100 System.out.println(o2.x); // Afiseaza 200 Aadar, fiecare obiect nou creat va putea memora valori diferite pentru variabilele sale de instan. Pentru variabilele de clas (statice) sistemul aloc o singur zon de memorie la care au acces toate instanele clasei respective, ceea ce nseamn c dac un obiect modific valoarea unei variabile statice ea se va modifica i pentru toate celelalte obiecte. Deoarece nu depind de o anumit instan a unei clase, variabilele statice pot fi referite i sub forma: NumeClasa.numeVariabilaStatica class Exemplu2 { int x ; // Variabila de instanta static long n; // Variabila de clasa } ... Exemplu2 o1 = new Exemplu2(); Exemplu2 o2 = new Exemplu2(); o1.n = 100; System.out.println(o2.n); // Afiseaza 100 o2.n = 200; System.out.println(o1.n); // Afiseaza 200 System.out.println(Exemplu2.n); // Afiseaza 200 // o1.n, o2.n si Exemplu2.n sunt referinte la aceeasi valoare Note Iniializarea variabilelor de clas se face o singur dat, la ncrcarea n

Programare orientat obiect memorie a clasei respective, i este realizat prin atribuiri obinuite: class Exemplu3 { static final double PI = 3.14; static long nrInstante = 0; } b) Metode de instan i de clas Similar ca la variabile, metodele declarate fr modificatorul static sunt metode de instan iar cele declarate cu static sunt metode de clas. Diferena ntre cele dou tipuri de metode este urmtoarea: metodele de instan opereaz att pe variabilele de instan ct i 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 } static void metodaStatica() { n++; // Corect x--; // Eroare la compilare ! } } Intocmai ca i la variabilele statice, ntruct metodele de clas nu depind de starea obiectelor clasei respective, apelul lor se poate face i sub forma: NumeClasa.numeMetodaStatica Exemplu.metodaStatica(); // Corect, echivalent cu Exemplu obj = new Exemplu(); obj.metodaStatica(); // Corect, de asemenea Metodele de instan nu pot fi apelate dect pentru un obiect al clasei respective: Exemplu.metodaDeInstanta(); // Eroare la compilare ! Exemplu obj = new Exemplu(); obj.metodaDeInstanta(); // Corect 2.1.5 Tablouri Tablourile n Java au suferit unele mbuntiri fa de modul de implementare al lor n alte limbaje cum ar fi C/C++. Astfel, tablourile sunt ntotdeauna iniializate i nu pot fi accesate nafara dimensiunilor stabilite la declararea lor. Tablourile n Java pot conine att tipuri de date primitive ct i date de tip referin (obiecte). a) Crearea unui vector Crearea unui vector presupune realizarea urmatoarelor etape: Declararea vectorului - Pentru a putea utiliza un vector trebuie, nainte de toate, s l declaram. Acest lucru se face prin expresii de forma: Tip[] numeVector; sau Tip numeVector[]; Exemple: int[] intregi; String adrese[];

33

Note

34

Programare orientat obiect Instanierea - Declararea unui vector nu implica i alocarea memoriei necesare pentru reinerea elementelor. Operaiunea de alocare a memoriei, numita i instanierea vectorului, se realizeaza ntotdeauna prin intermediul operatorului new. Instanierea unui vector se va face printr-o expresie de genul: numeVector = new Tip[nrElemente]; unde nrElemente reprezinta numarul maxim de elemente pe care le poate avea vectorul. n urma instanierii vor fi alocai: nrElemente*dimensiune(Tip) octei necesari memorarii elementelor din vector, unde prin dimensiune(Tip) am notat numarul de octei pe care se reprezinta tipul respectiv. Exemple: v = new int[10]; //aloca spatiu pentru 10 intregi: 40 octeti c = new char[10]; //aloca spatiu pentru 10 caractere: 20 octeti Declararea i instanierea unui vector pot fi facute simultan astfel: Tip[] numeVector = new Tip[nrElemente]; Iniializarea (opional): Dup declararea unui vector, acesta poate fi iniializat, adic elementele sale pot primi nite valori iniiale, evident dac este cazul pentru aa ceva. n acest caz instanierea nu mai trebuie facuta explicit, alocarea memoriei facndu-se automat n funcie de numarul de elemente cu care se iniializeaza vectorul. Exemple: String culori[] = {"Rosu", "Galben", "Verde"}; int []factorial = {1, 1, 2, 6, 24, 120}; Primul indice al unui vector este 0, deci poziiile unui vector cu n elemente vor fi cuprinse ntre 0 i n-1. Nu sunt permise construcii de genul Tip numeVector[nrElemente], alocarea memoriei facndu-se doar prin intermediul opearatorului new. int v[10]; //ilegal int v[] = new int[10]; //corect b) Dimensiunea unui vector Cu ajutorul variabilei length se poate afla numarul de elemente al unui vector. int []a = new int[5]; // a.length are valoarea 5 int m[][] = new int[5][10]; // m[0].length are valoarea 10 Pentru a nelege modalitatea de folosire a lui length trebuie menionat ca fiecare vector este de fapt o instana a unei clase iar length este o variabila publica a acelei clase, n care este reinut numarul maxim de elemente al vectorului. c) Metode pentru lucrul cu vectori Copierea vectorilor void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) unde src vector sursa ; dest vector destinatie ; length nr. de elemente de copiat Copierea elementelor unui vector a ntr-un alt vector b se poate face, fie element cu element, fie cu ajutorul metodei System.arraycopy, ca n exemplele de mai jos. Dup cum vom vedea, o atribuire de genul b = a are alta semnificaie dect copierea elementelor lui a n b i nu poate fi folosita n acest scop. int a[] = {1, 2, 3, 4}; int b[] = new int[4]; // Varianta 1 for(int i=0; i<a.length; i++)

Note

Programare orientat obiect b[i] = a[i]; // Varianta 2 System.arraycopy(a, 0, b, 0, a.length); // Nu are efectul dorit b = a; Metode din clasa Arrays n Java s-a pus un accent deosebit pe implementarea unor structuri de date i algoritmi care sa simplifice proceseul de crearea a unui algoritm, programatorul trebuind sa se concentreze pe aspectele specifice problemei abordate. Clasa java.util.Arrays ofera diverse metode statice foarte utile n lucrul cu vectori cum ar fi: void sort(vector[,indexInceput,indexSfarsit]) - sorteaza ascendent un vector, folosind un algoritm de tip Quick-Sort performant, de complexitate O(n log(n)). int v[]={3, 1, 4, 2}; java.util.Arrays.sort(v); // Sorteaza vectorul v // Acesta va deveni {1, 2, 3, 4} int binarySearch(tablou, valCautata) - cautarea binara a unei anumite valori ntr-un vector sortat; exista mai multe implementari ale metodei pentru vectori care contin diverse tipuri de date (char, int, float, double, long, Object); returneza indicele tablou unde a fost gasit elementul sau negativ. boolean equals(vector1, vector2) - testarea egalitaii valorilor a doi vectori (au aceleai numar de elemente i pentru fiecare indice valorile corespunzatoare din cei doi vectori sunt egale); exista mai multe implementari ale metodei pentru vectori care contin diverse tipuri de date (char, int, float, double, long, Object); returneaza true sau false. void fill(vector[,indexInceput, indexSfarsit],valFill) - atribuie fiecarui element dintr-un vector o valoare specificata; exista mai multe implementari ale metodei pentru vectori care contin diverse tipuri de date (char, int, float, double, long, Object). d) Tablouri multidimensionale n Java tablourile multidimensionale sunt de fapt vectori de vectori. De exemplu, crearea i instanierea unei matrici vor fi realizate astfel: Tip matrice[][] = new Tip[nrLinii][nrColoane]; matrice[i] este linia i a matricii i reprezinta un vector cu nrColoane elemente iar matrice[i][j] este elementul de pe linia i i coloana j. 2.1.6 iruri de caractere a) Clasa Character Clasa corespunztoare (wrapper) tipului primitiv char este clasa Character. Ea conine cteva metode statice uzuale care pot fi aplicate caracterelor. Cele mai importante sunt prezentate n tabelul de mai jos:
static int getNumericValue(char ch)

35

Returneaza valoarea ntreag asociat caracterului Unicode ch.


static boolean isDigit(char ch)

Determin dac parametrul ch este cifr.


static boolean isLetter(char ch)

Note

36

Programare orientat obiect Determin dac parametrul ch este liter.


static boolean isLetterOrDigit(char ch)

Determin dac parametrul ch este liter sau cifr.


static boolean isLowerCase(char ch)

Determin dac parametrul ch este liter mic.


static boolean isSpaceChar(char ch)

Determin dac parametrul ch este caracterul spaiu.


static boolean isUpperCase(char ch)

Determin dac parametrul ch este liter mare.


static boolean isWhitespace(char ch)

Determin dac parametrul ch este spaiu alb (spaiu, tab, etc).


static char toLowerCase(char ch)

Transform caracterul ch n liter mic.


static char toUpperCase(char ch)

Transform caracterul ch n liter mare. Exemplu de utilizare a metodelor: char c=a; if (Character.isLetter(c)) System.out.print(Este litera); b) iruri de caractere n Java, un ir de caractere poate fi reprezentat: printr-un vector format din elemente de tip char, un obiect de tip String sau un obiect de tip StringBuffer. Dac un ir de caractere este constant (nu se dorete schimbarea coninutului su pe parcursul execuiei programului) atunci el va fi declarat de tipul String, altfel va fi declarat de tip StringBuffer. Diferena principal ntre aceste clase este c StringBuffer pune la dispoziie metode pentru modificarea coninutului irului, cum ar fi: append, insert, delete, reverse. Uzual, cea mai folosit modalitate de a lucra cu iruri este prin intermediul clasei String, care are i unele particulariti fa de restul claselor menite s simplifice ct mai mult folosirea irurilor de caractere. Clasa StringBuffer va fi utilizat predominant n aplicaii dedicate procesrii textelor cum ar fi editoarele de texte. Exemple echivalente de declarare a unui ir: String s = "abc"; String s = new String("abc"); char data[] = {a, b, c}; String s = new String(data); Observai prima variant de declarare a irului s din exemplul de mai sus - de altfel, cea mai folosit - care prezint o particularitate a clasei String faa de restul claselor Java referitoare la instanierea obiectelor sale. Concatenarea irurilor de caractere se face prin intermediul operatorului + sau, n cazul irurilor de tip StringBuffer, folosind metoda append. String s1 = "abc" + "xyz"; String s2 = "123"; String s3 = s1 + s2; Note

Programare orientat obiect

37

c) Funcii pentru lucrul cu obiecte din clasa String


char charAt(int index)

Returneaz caracterul de pe poziia index din ir.


int compareTo(String anotherString)

Compar lexicografic dou iruri de caractere.


int indexOf(int ch, [int fromIndex])

Returneaz indexul din ir al primei apariii a caracterului ch, cutarea ncepnd opional de la poziia fromIndex (implicit de la nceput).
int indexOf(String str, [int fromIndex])

Returneaz indexul din ir al primei apariii a subirului


str, cutarea ncepnd opional de la poziia fromIndex

(implicit de la nceput).
int length()

Returneaz lungimea irului (numrul de caractere).


String replace(char oldChar, char newChar)

Returneaz un nou ir n care toate apariiile caracterului oldChar au fost nlocuite cu caracterul newChar.
String replaceAll(String regex, String replacement)

Returneaz un nou ir in care toate apariiile subirului regex au fost nlocuite cu subirul replacement.
String toLowerCase() / toUpperCase()

Transform toate literele irului n litere mici / mari.

d) Funcii pentru lucrul cu obiecte din clasa StringBuffer


StringBuffer append(String str) Adaug irul str de tip

String la sfritul irului

curent.
StringBuffer append(StringBuffer sb) Adaug irul sb de tip StringBuffer la sfritul curent. char charAt(int index)

irului

Returneaz caracterul de pe poziia index din ir.


StringBuffer deleteCharAt(int index)

terge din ir caracterul de pe poziia index (scurtnd irul cu un caracter).


int indexOf(String str, [int fromIndex])

Returneaz indexul din ir al primei apariii a subirului str, cutarea ncepnd opional de la poziia fromIndex (implicit de la nceput).
int length()

Returneaz lungimea irului (numrul de caractere). Note

38
StringBuffer

Programare orientat obiect

replace(int start, int end, String str) nlocuiete caracterele de la poziia start pn la poziia end din ir cu sirul de caractere str. void setCharAt(int index, char ch)

nlocuiete caracterul din ir de pe poziia index cu caracterul ch.


String toString()

Convertete irul de tip StringBuffer ntr-un ir de tip String.

Test de autoevaluare: 1. Care sunt principalele componente ale unei clase?

2. Care este diferena dintre membrii de clas (statici) i cei de instan ai unei clase?

3. Creai o clas cu numele Grup care are atributul de tip ntreg nrPersoane. Creai apoi un obiect al clasei Grup cu numele grupa1 i setai-i atributul nrPersoane la valoarea 30.

Note

Programare orientat obiect 4. Creai un tablou de tip caracter i iniializai-l cu valorile i, n, f, o. Aplicai-i apoi metoda sort.

39

5. Creai un ir de tip String i iniializai-l cu informatica. Cutai apoi n acest ir prima apariie a caracterului a, dup care transformai irul integral n litere mari.

Bibliografie : 1. Cristian Frsinaru Curs practic de Java 2. Bruce Eckel Thinking in Java 4th Edition, Ed. Prentice Hall, 2006, ISBN 0-13-187248-6 3. P. Niemeyer, J. Knudsen - Learning Java 3rd Edition, Ed. OReilly, 2005 4. .Tanas,.Andrei,C. Olaru Java de la 0 la expert, Ed.Polirom, 2007, ISBN 978-973-46-0317-6 5. D.Danciu, G.Mardale - Arta programrii n JAVA (Vol. I) Elemente-suport fundamentale, Ed. Albastr, 2005 Note

40 2.2 Motenirea

Programare orientat obiect

Obiective: Cunoaterea caracteristicilor motenirii n Java Cunoa tenirii Cunoaterea Cunoa terea folosirii la nevoie a mecanismelor suprancrcare i supradefinire a metodelor supranc Utilizarea claselor abstracte Utilizarea interfe interfeelor

de

2.2.1 Ce este mo motenirea? Motenirea este un concept de baz al programrii orientate obiect, unde tenirea baz rii toate clasele sunt aranjate ntr ierarhie strict. Fiecare clas din aceast ntr-o . clas ierarhie are o superclas (clase care se afl deasupra in ierahie) i un numr de superclas subclase (clase care se afl dedesupt n ierarhie). afl Prin motenire, o clas poate fi reutilizat pentru a modela o alta clas clas clas, care este o specializare a celei dinti. Prima clas se numeste clas de baz clas (superclas sau clas printe), iar cea de-a doua, clas derivat (sau subclas). clas ivat Clasele derivate mostenesc atributele i comportamentul de la i superclasele sale; constructorii nu se mostenesc. Deci se poate spune ca un obiect din clasa derivat este i un obiect de tipul clasei de baz Pe lng derivat i baz. atributele i met i metodele pe care le moteneste de la clasa de baz clasa derivat teneste baz, poate s adauge altele noi. Pentru a specifica c o subclas mo c moteneste o clas de baz, n Java se utilizeaz urmtoarea construcie: , utilizeaz [lista_Modificatori] class idClasa extends idClasaBaza { //corp_clasa } n cazul mo motenirii unei clase, instanierea unui obiect din clasa extins ierea extins implic instanierea unui obiect din clasa p rinte. Din acest motiv, fiecare ierea printe. constructor al clasei fiu va trebui s aib un constructor cu aceea signatur n s aceeai printe sau s apeleze explicit un constructor al clasei extinse folosind expresia super([argumente]), n caz contrar fiind semnalat o eroare la compilare. ([argumente]), semnalat 2.2.2 Supranc 2 Suprancrcarea i supradefinirea metodelor Suprancrcarea i supradefinirea metodelor sunt dou concepte extrem Supranc u de utile ale program programrii orientate obiect, cunoscute i sub denumirea de polimorfism, i se refer la: refer suprancarcarea ( (overloading) : n cadrul unei clase pot exista metode cu ) acelai nume cu condi ca signaturile lor s fie diferite (lista de argumente i condiia e primite s difere fie prin num rul argumentelor, fie prin tipul lor) astfel nct la numrul apelul funciei cu acel nume s se poat stabili n mod unic care dintre ele se iei s execut. supradefinirea ( (overriding): o subclas poate rescrie o metod a clasei printe metod prin implementarea unei metode cu acela nume i aceea signatur ca ale acelai i aceeai superclasei. Note class A { void metoda() {

Programare orientat obiect System.out.println("A: metoda fr parametru"); } // Supraincarcare void metoda(int arg) { System.out.println("A: metoda cu un parametru"); } } class B extends A { // Supradefinire void metoda() { System.out.println("B: metoda fr parametru"); } } O metod supradefinit poate s: ignore complet codul metodei corespunztoare din superclas (cazul de mai sus): B b = new B(); b.metoda(); // Afiseaza "B: metoda fr parametru" extind codul metodei printe, executnd nainte de codul propriu i funcia printelui: class B extends A { // Supradefinire prin extensie void metoda() { super.metoda(); System.out.println("B: metoda fr parametru"); } } ... B b = new B(); b.metoda(); /* Afiseaza ambele mesaje: "A: metoda fr parametru" "B: metoda fr parametru" */ O metod nu poate supradefini o metod declarat final n clasa printe. Orice clas care nu este abstract trebuie obligatoriu s supradefineasc metodele abstracte ale superclasei (dac este cazul). n cazul n care o clas nu supradefinete toate metodele abstracte ale printelui, ea nsi este abstract i va trebui declarat ca atare. n Java nu este posibil suprancrcarea operatorilor. 2.2.3 Clasa Object a) Orice clas are o superclas Dup cum am vzut n seciunea dedicat modalitii de creare a unei clase, clauza extends specific faptul c acea clas extinde (motenete) o alt clas, numit superclas. O clas poate avea o singur superclas (Java nu suport motenirea multipl) i chiar dac nu specificm clauza extends la crearea unei clase ea totui va avea o superclas. Cu alte cuvinte, n Java orice

41

Note

42

Programare orientat obiect clas are o superclas i numai una. Evident, trebuie s existe o excepie de la aceast regul i anume clasa care reprezint rdcina ierarhiei format de relaiile de motenire dintre clase. Aceasta este clasa Object. Clasa Object este i superclasa implicit a claselor care nu specific o anumit superclas. Declaraiile de mai jos sunt echivalente: class Exemplu {} class Exemplu extends Object {} b) Clasa Object Clasa Object este cea mai general dintre clasele Java, orice obiect fiind, direct sau indirect, descendent al ei. Fiind printele tuturor celorlalte clase, Object definete i implementeaz un comportament comun cum ar fi: posibilitatea testrii egalitii valorilor obiectelor, specificarea unei reprezentri ca ir de caractere a unui obiect , returnarea clasei din care face parte un obiect, notificarea altor obiecte c o variabil de condiie s-a schimbat, etc. Fiind subclas a lui Object, orice clas i poate supradefini metodele care nu sunt finale. Metodele cel mai uzual supradefinite sunt: clone, equals/hashCode, finalize, toString. clone: Aceast metod este folosit pentru duplicarea obiectelor (crearea unor clone). Clonarea unui obiect presupune crearea unui nou obiect de acelai tip i care s aib aceeai stare (aceleai valori pentru variabilele sale). Trebuie tiut c: TipReferinta o1 = new TipReferinta(); TipReferinta o2 = o1; nu face dect s declare o nou variabil o2 ca referina la obiectul referit de o1 i nu creeaz sub nici o form un nou obiect. n schimb: TipReferinta o1 = new TipReferinta(); TipReferinta o2 = (TipReferinta) o1.clone(); va crea un nou obiect. Deficiena acestei metode este c nu realizeaz duplicarea ntregii reele de obiecte corespunztoare obiectului clonat. n cazul n care exist cmpuri referina la alte obiecte, obiectele referite nu vor mai fi clonate la rndul lor. equals, hashCode: Acestea sunt, de obicei, supradefinite mpreun. n metoda equals este scris codul pentru compararea egalitii coninutului a dou obiecte. Implicit (implementarea din clasa Object), aceast metod compar referinele obiectelor. Uzual este redefinit pentru a testa dac strile obiectelor coincid sau dac doar o parte din variabilele lor coincid. Metoda hashCode returneaza un cod ntreg pentru fiecare obiect, pentru a testa consistena obiectelor: acelai obiect trebuie s returneze acelai cod pe durata execuiei programului. Dac dou obiecte sunt egale conform metodei equals, atunci apelul metodei hashCode pentru fiecare din cele dou obiecte ar trebui s returneze acelai intreg. finalize: n aceast metod se scrie codul care cur dup un obiect nainte de a fi eliminat din memorie de colectorul de gunoaie (garbage collector). toString: Este folosit pentru a returna o reprezentare ca ir de caractere a unui obiect. Este util pentru concatenarea irurilor cu diverse obiecte n vederea afirii, fiind apelat automat atunci cnd este necesar transformarea unui

Note

Programare orientat obiect obiect n ir de caractere. Deobicei, clasele care doresc afiarea obiectelor ca i iruri de caractere vor suprascrie aceast metod, modelnd-o dup propriile necesiti. Exemplu obj = new Exemplu(); System.out.println("Obiect=" + obj); //echivalent cu System.out.println("Obiect=" + obj.toString()); 2.2.4 Clase i metode abstracte Uneori n proiectarea unei aplicaii este necesar s reprezentm cu ajutorul claselor concepte abstracte care s nu poat fi instaniate i care s foloseasc doar la dezvoltarea ulterioar a unor clase ce descriu obiecte concrete. De exemplu, n pachetul java.lang exist clasa abstract Number care modeleaz conceptul generic de numr. ntr-un program nu avem ns nevoie de numere generice ci de numere de un anumit tip: ntregi, reale, etc. Clasa Number servete ca superclas pentru clasele concrete Byte, Double, Float, Integer, Long i Short, ce implementeaz obiecte pentru descrierea numerelor de un anumit tip. Aadar, clasa Number reprezint un concept abstract i nu vom putea instania obiecte de acest tip - vom folosi n schimb subclasele sale. Number numar = new Number(); // Eroare Integer intreg = new Integer(10); // Corect a) Declararea unei clase abstracte Declararea unei clase abstracte se face folosind cuvntul rezervat abstract: [public] abstract class ClasaAbstracta [extends Superclasa] [implements Interfata1, Interfata2, ...] { // Declaratii uzuale // Declaratii de metode abstracte } O clas abstract poate avea modificatorul public, accesul implicit fiind la nivel de pachet, dar nu poate specifica modificatorul final, combinaia abstract final fiind semnalat ca eroare la compilare - de altfel, o clas declarat astfel nu ar avea nici o utilitate. O clas abstract poate conine aceleai elemente membre ca o clas obinuit, la care se adaug declaraii de metode abstracte - fr nici o implementare. b) Metode abstracte Spre deosebire de clasele obinuite care trebuie s furnizeze implementri pentru toate metodele declarate, o clas abstract poate conine metode fr nici o implementare. Metodele fr nici o implementare se numesc metode abstracte i pot aprea doar n clase abstracte. n faa unei metode abstracte trebuie s apar obligatoriu cuvntul cheie abstract, altfel va fi furnizat o eroare de compilare. abstract class ClasaAbstracta { abstract void metodaAbstracta(); // Corect void metoda(); // Eroare } Note

43

44

Programare orientat obiect n felul acesta, o clas abstract poate pune la dispoziia subclaselor sale un model complet pe care trebuie s-l implementeze, furniznd chiar implementarea unor metode comune tuturor claselor i lsnd explicitarea altora fiecrei subclase n parte. Un exemplu elocvent de folosire a claselor i metodelor abstracte este descrierea obiectelor grafice ntr-o manier orientat-obiect. Obiecte grafice: linii, dreptunghiuri, cercuri, curbe Bezier, etc Stri comune: poziia(originea), dimensiunea, culoarea, etc Comportament: mutare, redimensionare, desenare, colorare, etc. Pentru a folosi strile i comportamentele comune acestor obiecte n avantajul nostru putem declara o clas generic GraphicObject care s fie superclas pentru celelalte clase. Metodele abstracte vor fi folosite pentru implementarea comportamentului specific fiecrui obiect, cum ar fi desenarea iar cele obinuite pentru comportamentul comun tuturor, cum ar fi schimbarea 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(); ... } O subclas care nu este abstract a unei clase abstracte trebuie s furnizeze obligatoriu implementri ale metodelor abstracte definite n superclas. Implementarea claselor pentru obiecte grafice ar fi: class Circle extends GraphicObject { void draw() { // Obligatoriu implementarea ... } } class Rectangle extends GraphicObject { void draw() { // Obligatoriu implementarea ... } }

Note

Programare orientat obiect Legat de metodele abstracte, mai trebuie menionate urmtoarele: O clas abstract poate s nu aib nici o metod abstract. O metod abstract nu poate aprea dect ntr-o clas abstract. Orice clas care are o metod abstract trebuie declarat ca fiind abstract. n API-ul oferit de platforma de lucru Java sunt numeroase exemple de ierarhii care folosesc la nivelele superioare clase abstracte. Dintre cele mai importante amintim: Number: superclasa abstract a tipurilor referin numerice Reader, Writer: superclasele abstracte ale fluxurilor de intrare/ieire pe caractere InputStream, OutputStream: superclasele abstracte ale fluxurilor de intrare/ieire pe octei AbstractList, AbstractSet, AbstractMap: superclase abstracte pentru structuri de date de tip colecie Component : superclasa abstract a componentelor folosite n dezvoltarea de aplicaii cu interfa grafic cu utilizatorul (GUI), cum ar fi Frame, Button, Label, etc. 2.2.5 Interfee a) Ce este o interfa ? Interfeele duc conceptul de clas abstract cu un pas nainte prin eliminarea oricror implementri de metode, punnd n practic unul din conceptele programrii orientate obiect i anume cel de separare a modelului unui obiect (interfa) de implementarea sa. Aadar, o interfa poate fi privita ca un protocol de comunicare ntre obiecte. O interfa Java definete un set de metode dar nu specific nici o implementare pentru ele. O clas care implementeaz o interfa trebuie obligatoriu s specifice implementri pentru toate metodele interfeei, supunndu-se aadar unui anumit comportament. Definiie: O interfa este o colecie de metode fr implementare i declaraii de constante. Interfeele permit, alturi de clase, definirea unor noi tipuri de date. b) Folosirea interfeelor b.1) Definirea unei interfee Definirea unei interfee se face prin intermediul cuvntului cheie interface: [public] interface NumeInterfata [extends SuperInterfata1, SuperInterfata2...] { /* Corpul interfetei: Declaratii de constane Declaratii de metode abstracte */ } O interfa poate avea un singur modificator i anume public. O interfa public este accesibil tuturor claselor, indiferent de pachetul din care fac parte, implicit nivelul de acces fiind doar la nivelul pachetului din care face parte interfaa. O interfa poate extinde oricte interfee. Acestea se numesc superinterfee i sunt separate prin virgul. Corpul unei interfee poate conine: Note

45

46

Programare orientat obiect constante: acestea pot fi sau nu declarate cu modificatorii public, static i final care sunt implicii, nici un alt modificator neputnd aprea n declaraia unei variabile dintr-o interfa. Constantele unei interfee trebuie obligatoriu iniializate. Exemplu: interface Exemplu { int MAX = 100; // Echivalent cu: public static final int MAX = 100; int MAX; // Incorect, lipseste initializarea private int x = 1; // Incorect, modificator nepermis } metode fr implementare: acestea pot fi sau nu declarate cu modificatorul public, care este implicit; nici un alt modificator nu poate aprea n declaraia unei metode a unei interfee. interface Exemplu { void metoda(); // Echivalent cu: public void metoda(); protected void metoda2(); // Incorect, modificator nepermis De reinut: Variabilele unei interfee sunt implicit publice chiar dac nu sunt declarate cu modificatorul public. Variabilele unei interfee sunt implicit constante chiar dac nu sunt declarate cu modificatorii static i final. Metodele unei interfee sunt implicit publice chiar dac nu sunt declarate cu modificatorul public. n variantele mai vechi de Java era permis i modificatorul abstract n declaratia interfeei i n declaraiile metodelor, ns acest lucru nu mai este valabil, deoarece att interfaa ct i metodele sale nu pot fi altfel dect abstracte. b.2) Implementarea unei interfee Implementarea uneia sau mai multor interfee de ctre o clas se face prin intermediul cuvntului cheie implements: class NumeClasa implements NumeInterfata sau class NumeClasa implements Interfata1, Interfata2, ... O clas poate implementa oricte interfee sau poate s nu implementeze nici una. n cazul n care o clas implementeaz o anumit interfa, atunci trebuie obligatoriu s specifice cod pentru toate metodele interfeei. Din acest motiv, odat creata i folosit la implementarea unor clase, o interfa nu mai trebuie modificat, n sensul c adugarea unor metode noi sau schimbarea signaturii metodelor existente vor duce la erori n compilarea claselor care o implementeaz. Evident, o clas poate avea i alte metode i variabile membre n afar de cele definite n interfa. Atenie! Modificarea unei interfee implic modificarea tuturor claselor care implementeaz acea interfa.

Note

Programare orientat obiect O interfa nu este o clas, dar orice referin de tip interfa poate primi ca valoare o referina la un obiect al unei clase ce implementeaz interfaa respectiv. Din acest motiv, interfeele pot fi privite ca tipuri de date i vom spune adesea c un obiect are tipul X, unde X este o interfa, dac acesta este o instan a unei clase ce implementeaz interfaa X. Implementarea unei interfee poate s fie i o clas abstract. c) Interfee i clase abstracte La prima vedere o interfa nu este altceva dect o clas abstract n care toate metodele sunt abstracte (nu au nici o implementare). Aadar, o clas abstract nu ar putea nlocui o interfa ? Raspunsul la intrebare depinde de situaie, ns n general este Nu. Deosebirea const n faptul c unele clase sunt forate s extind o anumit clas (de exemplu orice applet trebuie s fie subclasa a clasei Applet) i nu ar mai putea sa extind o alt clas, deoarece n Java nu exista dect motenire simpla. Fr folosirea interfeelor nu am putea fora clasa respectiv s respecte diverse tipuri de protocoale. La nivel conceptual, diferena const n: extinderea unei clase abstracte foreaz o relaie ntre clase; implementarea unei interfee specific doar necesitatea implementrii unor anumite metode. n multe situaii interfeele i clasele abstracte sunt folosite mpreun pentru a implementa ct mai flexibil i eficient o anumit ierarhie de clase. Un exemplu sugestiv este dat de clasele ce descriu colecii. Ca sa particularizm, exist: interfaa List care impune protocolul pe care trebuie s l respecte o clas de tip list, clasa abstract AbstractList care implementeaz interfaa List i ofer implementri concrete pentru metodele comune tuturor tipurilor de list, clase concrete, cum ar fi LinkedList, ArrayList care extind AbstractList. d) Motenire multipl prin interfee Interfeele nu au nici o implementare i nu pot fi instaniate. Din acest motiv, nu reprezint nici o problem ca anumite clase s implementeze mai multe interfee sau ca o interfa s extind mai multe interfee (s aib mai multe superinterfee) class NumeClasa implements Interfata1, Interfata2, ... interface NumeInterfata extends Interfata1, Interfata2, ... O interfa mosteneste att constantele ct i declaraiile de metode de la superinterfeele sale. O clas moteneste doar constantele unei interfee i responsabilitatea implementrii metodelor sale. Evident, pot aprea situaii de ambiguitate, atunci cnd exist constante sau metode cu aceleai nume n mai multe interfee, ns acest lucru trebuie ntotdeauna evitat, deoarece scrierea unui cod care poate fi confuz este un stil prost de programare. n cazul in care acest lucru se ntmpl, compilatorul nu va furniza eroare dect dac se ncearc referirea constantelor ambigue fr a le prefixa cu numele interfeei sau dac metodele cu acelai nume nu pot fi deosbite, cum ar fi situaia cnd au aceeai list de argumente dar tipuri returnate incompatibile. Exemplu: interface I1 { int x=1; void metoda();

47

Note

48 } interface I2 { int x=2; void metoda(); //corect //int metoda(); //incorect } class C implements I1, I2 { public void metoda() { System.out.println(I1.x); //corect System.out.println(I2.x); //corect System.out.println(x); //ambiguitate } }

Programare orientat obiect

e) Utilitatea interfeelor Dup cum am vzut, o interfa definete un protocol ce poate fi implementat de orice clas, indiferent de ierarhia de clase din care face parte. Interfeele sunt utile pentru: definirea unor similaritati ntre clase independente fr a fora artificial o legatur ntre ele; asigur c toate clasele care implementeaz o interfa pun la dipoziie metodele specificate n interfa - de aici rezult posibilitatea implementrii unor clase prin mai multe modaliti i folosirea lor ntr-o manier unitar; definirea unor grupuri de constante; transmiterea metodelor ca parametri; e.1) Crearea grupurilor de constante Deoarece orice variabil a unei interfee este implicit declarat cu public, static si final, interfeele reprezint o metod convenabil de creare a unor grupuri de constante care s fie folosite global ntr-o aplicaie: public interface Luni { int IAN=1, FEB=2, ..., DEC=12; } Folosirea acestor constante se face prin expresii de genul NumeInterfata.constanta, ca n exemplul de mai jos: if (luna < Luni.DEC) luna ++; else luna = Luni.IAN; e.2) Transmiterea metodelor ca parametri Deoarece nu exist pointeri propriu-zii, transmiterea metodelor ca parametri este realizat n Java prin intermediul interfeelor. Atunci cnd o metod trebuie s primeasc ca argument de intrare o referin la o alt funcie necesar execuiei sale, cunoscut doar la momentul execuiei, atunci argumentul respectiv va fi declarat de tipul unei interfee care conine metoda respectiv. La execuie metoda va putea primi ca parametru orice obiect ce implementeaz interfaa respectiv i deci conine i codul funciei respective, aceasta urmnd s fie apelat normal pentru a obine rezultatul dorit. Aceast tehnic, denumit i call-back, este extrem de folosit n Java i trebuie neaprat neleas. S considerm mai multe exemple pentru a clarifica lucrurile. Note

Programare orientat obiect

49

2.2.6 Adaptori n cazul n care o interfa conine mai multe metode i, la un moment dat, avem nevoie de un obiect care implementeaz interfaa respectiv dar nu specific cod dect pentru o singur metod, el trebui totui s implementeze toate metodele interfeei, chiar dac nu specific nici un cod. interface X { void metoda_1(); void metoda_2(); ... void metoda_n(); } ... // Avem nevoie de un obiect de tip X ca argument al unei functii functie(new X() { public void metoda_1() { // Singura metoda care ne intereseaza ... } // Trebuie sa apara si celelalte metode // chiar dac nu au implementare efectiva public void metoda_2() {} public void metoda_3() {} ... public void metoda_n() {} }); Aceast abordare poate fi neplcut dac avem frecvent nevoie de obiecte ale unor clase ce implementeaz interfaa X. Soluia la aceast problem este folosirea adaptorilor. Definiie: Un adaptor este o clas abstract care implementeaz o anumit interfa fr a specifica cod nici unei metode a interfeei. public abstract class XAdapter implements X { public void metoda_1() {} public void metoda_2() {} ... public void metoda_n() {} } n situaia cnd avem nevoie de un obiect de tip X vom folosi clasa abstract, supradefinind doar metoda care ne intereseaz: functie(new XAdapter() { public void metoda_1() { // Singura metoda care ne intereseaza ... } }); 2.2.7 Polimorfism Polimorfismul este nc unul din conceptele de baza ale programrii orientate obiect i se leag direct de noiunea de motenire. n cele ce urmeaz vom ilustra n ce const aceast noiune. Note

50

Programare orientat obiect n momentul n care se creaz o clas care motenete o alt clas, se va putea spune c noua clas este un fel de (a type of) clasa deja existent. Mai spuneam la nceputul acestui capitol c la crearea unui obiect din subclas se va crea i un obiect corespunztor din superclas. Astfel, un obiect poate fi privit ca fiind de tipul clasei creia i aparine sau de tipul clasei printe. A considera un obiect ca fiind de tipul clasei printe se numete upcasting. S lum urmtorul exemplu: class Instrument { public void play() {} static void tune(Instrument i) { // ... i.play(); } } public class InstrumentDeSuflat extends Instrument { public static void main(String[] args) { InstrumentDeSuflat flaut = new InstrumentDeSuflat(); Instrument.tune(flaut); // Upcasting } } Se observ c clasa InstrumentDeSuflat extinde clasa Instrument, ea motenind astfel metodele play() i tune() pe care nu le modifica n vreun fel. n cadrul clasei Instrument este definit metoda tune() care primete ca i parametru un obiect de tip Instrument. Se observ ns c n metoda main() a clasei InstrumentDeSuflat este apelat metoda tune() din clasa Instrument cu un parametru de tip InstrumentDeSuflat. Acest lucru va fi posibil tocmai din cauza a ceea ce spuneam mai sus i anume faptul c prin motenire, un obiect de tip InstrumentDeSuflat este un fel de Instrument, astfel c orice se poate face cu un obiect de tip Instrument poate fi fcut i cu un obiect de tip InstrumentDeSuflat (afirmaia invers nu mai este ntotdeauna adevrat). Utilitatea acestui fapt este dovedit de exemplu n cazul n care am deriva mai multe clase din clasa Instrument i ar trebui ca pentru fiecare dintre ele s scriem o metod tune() corespunzatoare. Efortul de a scrie o singur dat n clasa Instrument i a o putea apoi apela cu parametri din oricare din clasele derivate este net mai mic. Deasemenea, oricte alte clase s-ar mai deriva din clasa Instrument, toate se vor putea folosi de aceeai metod definit n clasa printe. class Nota { public static final Nota DO = new Nota("Do"), RE = new Nota("Re"), MI = new Nota("Mi"); private String noteName; private Nota(String noteName) { this.noteName = noteName; } public String toString() { return noteName; } } class Instrument { public void play(Nota n) {

Note

Programare orientat obiect } public static void tune(Instrument i) { i.play(Nota.DO); } } class InstrumentDeSuflat extends Instrument { public void play(Nota n) { System.out.println("InstrumentDeSuflat.play() " + n); } } class InstrumentCuCoarde extends Instrument { public void play(Nota n) { System.out.println("InstrumentCuCoarde.play() " + n); } } class InstrumentDePercutie extends Instrument { public void play(Nota n) { System.out.println("InstrumentDePercutie.play() " + n); } } public class Music { public static void main(String[] args) { Instrument flaut = new InstrumentDeSuflat(); Instrument vioara = new InstrumentCuCoarde(); Instrument trianglu = new InstrumentDePercutie(); Instrument.tune(flaut); // Upcasting Instrument.tune(vioara); Instrument.tune(trianglu); } } La rularea acestui cod se va obine: InstrumentDeSuflat.play() Do InstrumentCuCoarde.play() Do InstrumentDePercutie.play() Do Aadar, chiar dac n declararea sa, metoda tune() primete un parametru de tip Instrument i n cadrul su apeleaz metoda play(), se observ c la rulare, n cadrul celor 3 apeluri ale metodei tune() cu diveri parametri, se apeleaz defapt metodele play() corespunztoare fiecrui obiect transmis ca i parametru i nu metoda play() din clasa Instrument. Aparent acest lucru nu ar fi posibil dac nu ar exista implementat in Java tehnica numit late binding (legare trzie), numit i dynamic binding sau runtime binding, n contrast cu alte limbaje de programare care folosesc early binding (legare timpurie). Asocierea dintre apelul unei metode i corpul unei metode se numete binding. Atunci cnd acest lucru are loc nainte rulrii programului, se numete early binding, specific limbajelor de programare procedurale. Alternativa se numete late binding i const n asocierea dintre apelul unei metode i corpul unei metode n momentul rulrii programului. Pentru aceasta este nevoie de un mecanism care s determine tipul obiectului folosit i metoda corespunztoare lui.

51

Note

52

Programare orientat obiect

Test de autoevaluare: 1. Creai o clas care s aib o metod suprancrcat.

2. Creai o clas C1 care s conin metoda suma, iar apoi creai clasa C2 care extinde clasa C1 i suprascrie metoda motenit suma.

3. Enumerai diferenele dintre o clas abstract i o interfa.

4. Creai o clas care s extind o alt clas i s implementeze dou interfee.

Note

Programare orientat obiect

53

5. Care este utilitatea claselor de tip adaptor?

Bibliografie : 1. Cristian Frsinaru Curs practic de Java 2. Bruce Eckel Thinking in Java 4th Edition, Ed. Prentice Hall, 2006, ISBN 0-13-187248-6 3. P. Niemeyer, J. Knudsen - Learning Java 3rd Edition, Ed. OReilly, 2005 4. .Tanas,.Andrei,C. Olaru Java de la 0 la expert, Ed.Polirom, 2007, ISBN 978-973-46-0317-6 5. D.Danciu, G.Mardale - Arta programrii n JAVA (Vol. I) Elemente-suport fundamentale, Ed. Albastr, 2005 Note

54 2.3 Excepii

Programare orientat obiect

Obiective: Cunoaterea caracteristicilor i a utilitaii folosirii excep Cunoa ii excepiilor n programe Cunoaterea diverselor modaliti de lucru cu excep Cunoa i excepiile Crearea de excep proprii excepii

Note

2.3.1 Ce sunt excep .1 excepiile ? Termenul excep este o prescurtare pentru eveniment excep excepie niment excepional i poate fi definit ca un eveniment ce se produce n timpul execu execuiei unui program i care provoac ntreruperea cursului normal al execu iei acestuia. i execuiei Excepiile pot ap iile aprea din diverse cauze i pot avea nivele diferite de i gravitate: de la erori fatale cauzate de echipamentul hardware pn la erori ce in pn strict de codul programului, cum ar fi accesarea unui element din afara spa spaiului alocat unui vector. n momentul cnd o asemenea eroare se produce n timpul execu execuiei va fi generat un obiect de tip excep ce conine: excepie informa despre excepia respectiv; informaii starea programului n momentul producerii acelei excep excepii. Exemplu: public class Exemplu { public static void main(String args[]) { int v[] = new int[10]; v[10] = 0; //Exceptie ! System.out.println("Aici nu se mai ajunge..."); } } La rularea programului va fi generat o excepie, programul se va opri la generat ie, instruciunea care a cauzat excep i se va afia un mesaj de eroare de genul: iunea excepia a "Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException :10 at hread Exceptii.main (Exceptii.java:4)" Crearea unui obiect de tip excep se mai numete si aruncarea unei excepie te excepii (throwing an exception). n momentul n care o metod genereaz ii metod (arunc) o excep ) excepie sistemul de execuie este responsabil cu g ie gsirea unei secvene de cod dintr metod care s o trateze. Cutarea se face recursiv, e dintr-o utarea ncepnd cu metoda care a generat excep i mergnd napoi pe linia apelurilor excepia i ctre acea metod tre metod. Secvena de cod dintr metod care trateaz o anumit excepie se a dintr-o anumit numete analizor de excep ie (exception handler), iar interceptarea i tratarea te excepie ei se numete prinderea excep te excepiei (catch the exception). Cu alte cuvinte, la apari ia unei erori este aruncat o excepie iar apariia aruncat cineva trebuie s o prind pentru a o trata. Dac sistemul nu gase nici un gasete analizor pentru o anumit excepie, atunci programul Java se opre anumit ie, oprete cu un mesaj de eroare (n cazul exemplului de mai sus mesajul Aici nu se mai ajunge... nu va fi afi afiat).

Programare orientat obiect n Java tratarea erorilor nu mai este o opiune ci o constrngere! n aproape toate situaile, o secven de cod care poate provoca excepii trebuie s specifice modalitatea de tratare a acestora. 2.3.2 Ierarhia claselor ce descriu excepii Rdcina claselor ce descriu excepii este clasa Throwable iar cele mai importante subclase ale sale sunt Error, Exception i RuntimeException, care sunt la rndul lor superclase pentru o serie ntreag de tipuri de excepii.
Throwable

55

Error

Exception

RuntimeException

IOException

FileNotFoundException

Erorile, obiecte de tip Error, sunt cazuri speciale de excepii generate de funcionarea anormal a echipamentului hard pe care ruleaz un program Java i sunt invizibile programatorilor. Un program Java nu trebuie s trateze apariia acestor erori i este improbabil ca o metod Java s provoace asemenea erori. Excepiile, obiectele de tip Exception, sunt excepiile standard (soft) care trebuie tratate de ctre programele Java. Dup cum am mai zis tratarea acestor excepii nu este o opiune ci o constrngere. Excepiile care pot scpa netratate descind din subclasa RuntimeException i se numesc excepii la execuie. Metodele care sunt apelate uzual pentru un obiect excepie sunt definite n clasa Throwable i sunt publice, astfel nct pot fi apelate pentru orice tip de excepie. Cele mai uzuale sunt: getMessage - afieaz detaliul unei excepii; printStackTrace - afieaz informaii complete despre excepie i localizarea ei; toString - metod motenit din clasa Object, care furnizeaz reprezentarea ca ir de caractere a excepiei. 2.3.3 Prinderea i tratarea excepiilor Tratarea excepiilor se realizeaz prin intermediul blocurilor de instruciuni try, catch i finally (opional). O secven de cod care trateaz anumite excepii trebuie s arate astfel: try { // Instructiuni care pot genera exceptii } catch (TipExceptie1 variabila) { // Tratarea exceptiilor de tipul 1 } catch (TipExceptie2 variabila) { // Tratarea exceptiilor de tipul 2 } Note

56

Programare orientat obiect ... finally { // Cod care se executa indiferent // dac apar sau nu exceptii } S considerm urmtorul exemplu: citirea unui fiier octet cu octet i afisarea lui pe ecran. Fr a folosi tratarea excepiilor metoda responsabil cu citirea fiierului ar arta astfel: public static void citesteFisier(String fis) { FileReader f = null; // Deschidem fisierul System.out.println("Deschidem fisierul " + fis); f = new FileReader(fis); // Citim si afisam fisierul caracter cu caracter int c; while ( (c=f.read()) != -1) System.out.print((char)c); // Inchidem fisierul System.out.println("\\nInchidem fisierul " + fis); f.close(); } Aceast secven de cod va furniza erori la compilare deoarece n Java tratarea erorilor este obligatorie. Folosind mecanismul excepiilor, metoda citeste i poate trata singur erorile care pot surveni pe parcursul execuiei sale. Blocul try contine instruciunile de deschidere a unui fiier i de citire dintr-un fiier, ambele putnd produce excepii. Excepiile provocate de aceste instruciuni sunt tratate n cele dou blocuri catch, cte unul pentru fiecare tip de excepie. Inchiderea fiierului se face n blocul finally, deoarece acesta este sigur c se va executa Fr a folosi blocul finally, nchiderea fiierului ar fi trebuit facut n fiecare situaie n care fiierul ar fi fost deschis, ceea ce ar fi dus la scrierea de cod redundant. try { ... // Totul a decurs bine. f.close(); } ... catch (IOException e) { ... // A aparut o exceptie la citirea din fisier f.close(); // cod redundant } O problem mai delicat care trebuie semnalata n aceasta situaie este faptul c metoda close, responsabil cu nchiderea unui fiier, poate provoca la rndul su excepii, de exemplu atunci cnd fiierul mai este folosit i de alt proces i nu poate fi nchis. Deci, pentru a avea un cod complet corect trebuie s tratm i posibilitatea apariiei unei excepii la metoda close. Atenie! Obligatoriu un bloc de instruciuni try trebuie s fie urmat de unul sau mai multe blocuri catch, n funcie de excepiile provocate de acele instruciuni sau (opional) de un bloc finally. Note

Programare orientat obiect

57

2.3.4 Aruncarea excepiilor de ctre o metod n cazul n care o metod nu i asum responsabilitatea tratrii uneia sau mai multor excepii pe care le pot provoca anumite instruciuni din codul su atunci ea poate s arunce aceste excepii ctre metodele care o apeleaz, urmnd ca acestea s implementeze tratarea lor sau, la rndul lor, s arunce mai departe excepiile respective. Acest lucru se realizeaz prin specificarea n declaraia metodei a clauzei throws: [modificatori] TipReturnat metoda([argumente]) throws TipExceptie1, TipExceptie2, ... { ... } Atenie! O metod care nu trateaz o anumit excepie trebuie obligatoriu s o arunce. Metoda apelant poate arunca la rndul sau excepiile mai departe ctre metoda care a apelat-o la rndul ei. Aceast nlnuire se termin cu metoda main care, dac va arunca excepiile ce pot aprea n corpul ei, va determina trimiterea excepiilor ctre maina virtual Java. Exemplu: public void metoda3 throws TipExceptie { ... } public void metoda2 throws TipExceptie { metoda3(); } public void metoda1 throws TipExceptie { metoda2(); } public void main throws TipExceptie { metoda1(); } Tratarea excepiilor de ctre JVM se face prin terminarea programului i afiarea informaiilor despre excepia care a determinat acest lucru. Intotdeauna trebuie gsit compromisul optim ntre tratarea local a excepiilor i aruncarea lor ctre nivelele superioare, astfel nct codul s fie ct mai clar i identificarea locului n care a aprut excepia s fie ct mai uor de fcut. Aruncarea unei excepii se poate face i implicit prin instruciunea throw ce are formatul: throw exceptie, ca n exemplele de mai jos: throw new IOException("Exceptie I/O"); ... if (index >= vector.length) throw new ArrayIndexOutOfBoundsException(); ... catch(Exception e) { System.out.println("A aparut o exceptie); throw e; } Aceast instruciune este folosit mai ales la aruncarea excepiilor proprii.

Note

58

Programare orientat obiect 2.3.5 Avantajele tratrii excepiilor Prin modalitatea sa de tratare a excepiilor, Java are urmtoarele avantaje fa de mecanismul tradiional de tratare a erorilor: Separarea codului pentru tratarea unei erori de codul n care ea poate s apar. Propagarea unei erori pn la un analizor de excepii corespunztor. Gruparea erorilor dup tipul lor. 2.3.6 Excepii la execuie n general, tratarea excepiilor este obligatorie n Java. De la acest principu se sustrag ns aa numitele excepii la execuie sau, cu alte cuvinte, excepiile care provin strict din vina programatorului i nu generate de o anumit situaie extern, cum ar fi lipsa unui fiier. Aceste excepii au o superclas comun RuntimeException i n acesata categorie sunt incluse excepiile provocate de: operaii aritmetice ilegale (mprirea ntregilor la zero) - ArithmeticException accesarea membrilor unui obiect ce are valoarea null - NullPointerException a elementelor unui vector accesarea eronat ArrayIndexOutOfBoundsException Excepiile la execuie pot aprea oriunde n program i pot fi extrem de numeroase, iar ncercarea de prindere a lor ar fi extrem de anevoioas. Din acest motiv, compilatorul permite ca aceste excepii s rmn netratate, tratarea lor nefiind ns ilegal. Reamintim ns c, n cazul apariiei oricrui tip de excepie care nu are un analizor corespunztor, programul va fi terminat. 2.3.7 Excepii definite de utilizator Poate apare uneori necesitatea crerii unor excepii proprii pentru a pune n eviden cazuri speciale de erori, cazuri care un au fost prevazute n ierarhia excepiilor standard Java. O clasa de exceptii proprie trebuie s implementeze una din clasele de excepii deja existente, n cazul cel mai general, trebuie sa implementeze clasa Exception. Exemplu: class MyException extends Exception { MyException () {} MyException (String msg){ super(msg); } }

Test de autoevaluare: 1. Ce conin blocurile try, catch, finally?

Note

Programare orientat obiect

59

2. Cte blocuri try i cte blocuri catch pot exista ntr-o construcie trycatch-finally?

3. Care este cuvntul cheie folosit de o metod care nu dorete s trateze excepiile i vrea s le arunce la nivelele superioare?

4. Care este diferena dintre erori i excepii?

5. Care este particularitatea clasei RuntimeException?

Bibliografie : 1. Cristian Frsinaru Curs practic de Java 2. Bruce Eckel Thinking in Java 4th Edition, Ed. Prentice Hall, 2006, ISBN 0-13-187248-6 3. P. Niemeyer, J. Knudsen - Learning Java 3rd Edition, Ed. OReilly, 2005 4. .Tanas,.Andrei,C. Olaru Java de la 0 la expert, Ed.Polirom, 2007, ISBN 978-973-46-0317-6 5. D.Danciu, G.Mardale - Arta programrii n JAVA (Vol. I) Elemente-suport fundamentale, Ed. Albastr, 2005 Note

60

Programare orientat obiect 2.4 Intrri i ieiri. Fluxuri

Obiective: Cunoaterea noiunii de flux n Java Cunoa Cunoaterea principalelor tipuri de fluxuri i utilitatea lor Cunoa Cunoaterea fluxurilor pentru intrarea i ieirea standard Cunoa irea Cunoaterea posibilitailor de citire a datelor de la tastatur Cunoa ilor tastatur Lucrul cu fi iere folosind clasa RandomAccessFile fiiere Lucrul cu fi fiiere folosind clasa File

2.4.1 Introducere 1 a) Ce sunt fluxurile? Majoritatea aplica aplicaiilor necesit citirea unor informaii care se g gsesc pe o surs extern sau trimiterea unor informaii ctre o destina tre destinaie extern. Informaia se poate g oriunde: ntr-un fiier pe disc, n reea, n memorie sau ia gsi ier n alt program i poate fi de orice tip: date primitive, obiecte, imagini, sunete, i etc. Pentru a aduce informa dintr-un mediu extern, un progam Java trebuie informaii un s deschid un canal de comunica (flux) de la sursa informa comunicaie ) informaiilor (fiier, memorie, socket, etc) i s citeasc secvenial informaiile respective. iile Similar, un program poate trimite informa ctre o destina extern informaii tre destinaie deschiznd un canal de comunica comunicaie (flux) ctre acea destina tre destinaie i scriind secvenial informa ial informaiile respective. Indiferent de tipul informa iilor, citirea/scrierea de pe/c informaiilor, pe/ctre un mediu extern respect urm urmtorul algoritm: ieire deschide canal comunicatie while (mai sunt informatii) { Program Java Surs extern citeste/scrie informatie; } intrare inchide canal comunicatie; Pentru a generaliza, att sursa extern a unor date ct i destinaia lor extern sunt vzute ca fiind ni te procese care produc, respectiv consum informaii. zute nite consum Definiii: - Un flux este un canal de comunica unidirecional ntre dou procese. comunicaie ional dou - Un proces care descrie o surs extern de date se nume surs numete proces productor. - Un proces care descrie o destina extern pentru date se nume proces destinaie numete consumator. - Un flux care cite date se numete flux de intrare. citete - Un flux care scrie date se nume flux de ieire. numete Observaii: Fluxurile sunt canale de comunica ie seriale pe 8 sau 16 bi comunicaie bii. Fluxurile sunt unidirec unidirecionale, de la productor la consumator. tor Fiecare flux are un singur proces produc x productor i un singur proces consumator. i Intre dou procese pot exista oricte fluxuri, orice proces putnd fi att producator ct i consumator n acela i timp, dar pe fluxuri diferite. acelai Consumatorul i producatorul nu comunic direct printr-o interfa de flux ci o interfa

Note

Programare orientat obiect prin intermediul codului Java de tratare a fluxurilor. Clasele i intefeele standard pentru lucrul cu fluxuri se gsesc n pachetul java.io. Deci, orice program care necesit operaii de intrare sau ieire trebuie s conin instruciunea de import a pachetului java.io: import java.io.*; b) Clasificarea fluxurilor Exist trei tipuri de clasificare a fluxurilor: Dup direcia canalului de comunicaie deschis fluxurile se mpart n: fluxuri de intrare (pentru citirea datelor) fluxuri de ieire (pentru scrierea datelor) Dup tipul de date pe care opereaz: fluxuri de octei (comunicarea serial se realizeaz pe 8 bii) fluxuri de caractere (comunicarea serial se realizeaz pe 16 bii) Dup aciunea lor: fluxuri primare de citire/scriere a datelor (se ocup efectiv cu citirea/scrierea datelor) fluxuri pentru procesarea datelor c) Ierarhia claselor pentru lucrul cu fluxuri Clasele rdcin pentru ierarhiile ce reprezint fluxuri de caractere sunt: Reader- pentru fluxuri de intrare i Writer- pentru fluxuri de ieire. Acestea sunt superclase abstracte pentru toate clasele ce implementeaz fluxuri specializate pentru citirea/scrierea datelor pe 16 bii i vor conine metodele comune tuturor. Ca o regul general, toate clasele din aceste ierarhii vor avea terminaia Reader sau Writer n funcie de tipul lor, cum ar fi n exemplele: FileReader, BufferedReader, FileWriter, BufferedWriter, etc. De asemenea, se observ ca o alt regul general, faptul c unui flux de intrare XReader i corespunde uzual un flux de ieire XWriter, ns acest lucru nu este obligatoriu. Clasele radacin pentru ierarhia fluxurilor de octei sunt: InputStream- pentru fluxuri de intrare i OutputStream- pentru fluxuri de ieire. Acestea sunt superclase abstracte pentru clase ce implementeaz fluxuri specializate pentru citirea/scrierea datelor pe 8 bii. Ca i n cazul fluxurilor pe caractere denumirile claselor vor avea terminaia superclasei lor: FileInputStream, BufferedInputStream, FileOutputStream, BufferedOutputStream, etc., fiecrui flux de intrare XInputStream corespunzndu-i uzual un flux de ieire XOutputStream, fr ca acest lucru s fie obligatoriu. Pn la un punct, exist un paralelism ntre ierarhia claselor pentru fluxuri de caractere i cea pentru fluxurile pe octei. Pentru majoritatea programelor este recomandat ca scrierea i citirea datelor s se fac prin intermediul fluxurilor de caractere, deoarece acestea permit manipularea caracterelor Unicode n timp ce fluxurile de octei permit doar lucrul pe 8 biti - caractere ASCII. d) Metode comune fluxurilor Superclasele abstracte Reader i pentru citirea datelor. Reader int read() int read (char buf[]) InputStream definesc metode similare InputStream int read() int read (char buf[])

61

Note

62

Programare orientat obiect ... ... De asemenea, ambele clase pun la dispoziie metode pentru marcarea unei locaii ntr-un flux, saltul peste un numr de poziii, resetarea poziiei curente, etc. Acestea sunt ns mai rar folosite i nu vor fi detaliate. Superclasele abstracte Writer i OutputStream sunt de asemenea paralele, definind metode similare pentru scrierea datelor: Reader InputStream void write (int c) void write (int c) void write (char buf[]) void write (char buf[]) void write (String str) ... ... Inchiderea oricrui flux se realizeaz prin metoda close(). n cazul n care aceasta nu este apelat explicit, fluxul va fi automat nchis de ctre colectorul de gunoaie atunci cnd nu va mai exista nici o referin la el, ns acest lucru trebuie evitat deoarece, la lucrul cu fluxrui cu zon tampon de memorie, datele din memorie vor fi pierdute la nchiderea fluxului de ctre gc. Metodele referitoare la fluxuri pot genera excepii de tipul IOException sau derivate din aceast clas, tratarea lor fiind obligatorie. Aa cum am vzut, fluxurile pot fi mprite n funcie de activitatea lor n fluxuri care se ocup efectiv cu citirea/scrierea datelor i fluxuri pentru procesarea datelor (de filtrare). n continuare, vom vedea care sunt cele mai importante clase din cele dou categorii i la ce folosesc acestea, precum i modalitile de creare i utilizare a fluxurilor. 2.4.2 Fluxuri primitive Fluxurile primitive sunt responsabile cu citirea/scrierea efectiv a datelor, punnd la dispoziie implementri ale metodelor de baz read, respectiv write, definite n superclase. n funcie de tipul sursei datelor, ele pot fi mprite astfel: Fiier : FileReader, FileWriter, FileInputStream, FileOutputStream Numite i fluxuri fiier, acestea sunt folosite pentru citirea datelor dintrun fiier, respectiv scrierea datelor ntr-un fiier i vor fi analizate ntr-o seciune separat. Memorie : CharArrayReader, CharArrayWriter, ByteArrayInputStream, ByteArrayOutputStream Aceste fluxuri folosesc pentru scrierea/citirea informaiilor n/din memorie i sunt create pe un vector existent deja. Cu alte cuvinte, permit tratarea vectorilor ca surs/destinaie pentru crearea unor fluxuri de intrare/ieire. StringReader, StringWriter permit tratarea irurilor de caractere aflate n memorie ca surs/destinaie pentru crearea de fluxuri. Pipe : PipedReader, PipedWriter, PipedInputStream, PipedOutputStream Implementeaz componentele de intrare/ieire ale unei conducte de date (pipe). Pipe-urile sunt folosite pentru a canaliza ieirea unui program sau fir de execuie ctre intrarea altui program sau fir de execuie. 2.4.3 Fluxuri de procesare Fluxurile de procesare (sau de filtrare) sunt responsabile cu preluarea datelor de la un flux primitiv i procesarea acestora pentru a le oferi ntr-o alt

Note

Programare orientat obiect form, mai util dintr-un anumit punct de vedere. De exemplu, BufferedReader poate prelua date de la un flux FileReader i s ofere informaia dintr-un fiier linie cu linie. Fiind primitiv, FileReader nu putea citi dect caracter cu caracter. Un flux de procesare nu poate fi folosit dect mpreun cu un flux primitiv. Clasele ce descriu aceste fluxuri pot fi mpartite n funcie de tipul de procesare pe care l efectueaza astfel: Bufferizare : BufferedReader, BufferedWriter, BufferedInputStream, BufferedOutputStream Sunt folosite pentru a introduce un buffer n procesul de citire/scriere a informaiilor, reducnd astfel numrul de accesri la dispozitivul ce reprezint sursa/destinaia original a datelor. Sunt mult mai eficiente dect fluxurile fr buffer i din acest motiv se recomand folosirea lor ori de cte ori este posibil. Filtrare: FilterReader, FilterWriter, FilterInputStream, FilterOutputStream Sunt clase abstracte ce definesc o interfa comun pentru fluxuri care filtreaz automat datele citite sau scrise. Conversie octei-caractere: InputStreamReader, OutputStreamWriter Formeaz o punte de legatur ntre fluxurile de caractere i fluxurile de octei. Un flux InputStreamReader citete octei dintr-un flux InputStream i i convertete la caractere, folosind codificarea standard a caracterelor sau o codificare specificat de program. Similar, un flux OutputStreamWriter convertete caractere n octei i trimite rezutatul ctre un flux de tipul OutputStream. Concatenare: SequenceInputStream Concateneaz mai multe fluxuri de intrare ntr-unul singur. Serializare: ObjectInputStream, ObjectOutputStream Sunt folosite pentru serializarea obiectelor. Conversie tipuri de date: DataInputStream, DataOutputStream Folosite la scrierea/citirea datelor de tip primitiv ntr-un format binar, independent de maina pe care se lucreaz. Numrare: LineNumberReader, LineNumberInputStream Ofer i posibilitatea de numrare automat a liniilor citite de la un flux de intrare. Citire n avans: PushbackReader, PushbackInputStream Sunt fluxuri de intrare care au un buffer de 1-caracter(octet) n care este citit n avans i caracterul (octetul) care urmeaz celui curent citit. Afiare: PrintWriter, PrintStream Ofer metode convenabile pentru afisarea informaiilor. 2.4.4 Crearea unui flux Orice flux este un obiect al clasei ce implementeaz fluxul respectiv. Crearea unui flux se realizeaz aadar similar cu crearea obiectelor, prin instruciunea new i invocarea unui constructor corespunztor al clasei respective: Exemple: //crearea unui flux de intrare pe caractere FileReader in = new FileReader("fisier.txt"); //crearea unui flux de iesire pe caractere FileWriter out = new FileWriter("fisier.txt");

63

Note

64

Programare orientat obiect //crearea unui flux de intrare pe octeti FileInputStream in = new FileInputStream("fisier.dat"); //crearea unui flux de iesire pe octeti FileOutputStrem out = new FileOutputStream("fisier.dat"); Aadar, crearea unui flux primitiv de date care citete/scrie informaii de la un dispozitiv extern are formatul general: FluxPrimitiv numeFlux = new FluxPrimitiv(dispozitivExtern); Fluxurile de procesare nu pot exista de sine stttoare ci se suprapun pe un flux primitiv de citire/scriere a datelor. Din acest motiv, constructorii claselor pentru fluxurile de procesare nu primesc ca argument un dispozitiv extern de memorare a datelor ci o referina la un flux primitiv responsabil cu citirea/scrierea efectiv a datelor: Exemple: //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(fr); //crearea unui flux de iesire printr-un buffer BufferedWriter out = new BufferedWriter(new FileWriter("fisier.txt"))); //echivalent cu FileWriter fo = new FileWriter("fisier.txt"); BufferedWriter out = new BufferedWriter(fo); Aadar, crearea unui flux pentru procesarea datelor are formatul general: FluxProcesare numeFlux = new FluxProcesare(fluxPrimitiv); n general, fluxurile pot fi compuse n succesiuni orict de lungi: DataInputStream in = new DataInputStream(new BufferedInputStream (new FileInputStream ("fisier.dat"))); 2.4.5 Fluxuri pentru lucrul cu fiiere Fluxurile pentru lucrul cu fiiere sunt cele mai usor de nteles, ntruct operaia lor de baz este citirea, respectiv scrierea unui caracter sau octet dintrun sauntr-un fiier specificat uzual prin numele su complet sau relativ la directorul curent. Dup cum am vzut deja, clasele care implementeaz aceste fluxuri sunt urmtoarele: FileReader, FileWriter - caractere FileInputStream, FileOutputStream - octeti Constructorii acestor clase accept ca argument un obiect care s specifice un anume fiier. Acesta poate fi un ir de caractere, on obiect de tip File sau un obiect de tip FileDesciptor. Constructorii clasei FileReader sunt: public FileReader(String fileName) throws FileNotFoundException public FileReader(File file) throws FileNotFoundException public FileReader(FileDescriptor fd) Constructorii clasei FileWriter: public FileWriter(String fileName) throws IOException public FileWriter(File file) throws IOException public FileWriter(FileDescriptor fd)

Note

Programare orientat obiect public FileWriter(String fileName, boolean append) throws IOException Cei mai uzuali constructori sunt cei care primesc ca argument numele fiierului. Acetia pot provoca excepii de tipul FileNotFoundException n cazul n care fiierul cu numele specificat nu exist. Din acest motiv orice creare a unui flux de acest tip trebuie fcut ntr-un bloc try-catch sau metoda n care sunt create fluxurile respective trebuie s arunce excepiile de tipul FileNotFoundException sau de tipul superclasei IOException. 2.4.6 Citirea i scrierea cu buffer Clasele pentru citirea/scrierea cu zona tampon (buffer) sunt: BufferedReader, BufferedWriter - caractere BufferedInputStream, BufferedOutputStream - octeti Sunt folosite pentru a introduce un buffer (zon de memorie) n procesul de citire/scriere a informaiilor, reducnd astfel numarul de accesri ale dispozitivului ce reprezint sursa/destinaia datelor. Din acest motiv, sunt mult mai eficiente dect fluxurile fr buffer i din acest motiv se recomand folosirea lor ori de cte ori este posibil. Clasa BufferedReader citete n avans date i le memoreaz ntr-o zon tampon. Atunci cnd se execut o operaie de citire, caracterul va fi preluat din buffer. n cazul n care buffer-ul este gol, citirea se face direct din flux i, odat cu citirea caracterului, vor fi memorati n buffer i caracterele care i urmeaz. Evident, BufferedInputStream funcioneaz dup acelai principiu, singura diferen fiind faptul c sunt citii octei. Similar lucreaza i clasele BufferedWriter i BufferedOutputStream. La operaiile de scriere datele scrise nu vor ajunge direct la destinaie, ci vor fi memorate ntr-un buffer de o anumit dimensiune. Atunci cnd bufferul este plin, coninutul acestuia va fi transferat automat la destinaie. Fluxurile de citire/scriere cu buffer sunt fluxuri de procesare i sunt folosite prin suprapunere cu alte fluxuri, dintre care obligatoriu unul este primitiv. Ex: BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("out.dat"), 1024) //1024 este dimensiunea bufferului Constructorii cei mai folosii ai acestor clase sunt urmtorii: BufferedReader(Reader in) BufferedReader(Reader in, int dim_buffer) BufferedWriter(Writer out) BufferedWriter(Writer out, int dim_buffer) BufferedInputStream(InputStream in) BufferedInputStream(InputStream in, int dim_buffer) BufferedOutputStream(OutputStream out) BufferedOutputStream(OutputStream out, int dim_buffer) n cazul constructorilor n care dimensiunea buffer-ului nu este specificat, aceasta primete valoarea implicit de 512 octei (caractere). Metodele acestor clase sunt cele uzuale de tipul read i write. Pe lnga acestea, clasele pentru scriere prin buffer mai au i metoda flush() care golete explicit zona tampon, chiar dac aceasta nu este plin. Exemplu: BufferedWriter out = new BufferedWriter(new FileWriter("out.dat"), 1024) //am creat un flux cu buffer de 1024 octeti

65

Note

66

Programare orientat obiect for(int i=0; i<1000; i++) out.write(i); //bufferul nu este plin, in fisier nu s-a scris nimic out.flush(); //bufferul este golit, datele se scriu in fisier Metoda readLine(): Este specific fluxurilor de citire cu buffer i permite citirea linie cu linie a datelor de intrare. O linie reprezint o succesiune de caractere terminat cu simbolul pentru sfrit de linie, dependent de platforma de lucru. Acesta este reprezentat n Java prin secvena escape \n; Exemplu: BufferedReader br = new BufferedReader(new FileReader("in")); String linie; while ((linie = br.readLine()) != null) { ... //proceseaza linie } br.close(); 2.4.7 Clasele DataInputStream i DataOutputStream Aceste clase ofer metode prin care un flux nu mai este vzut ca o nsiruire de octei, ci de date primitive. Prin urmare, vor furniza metode pentru citirea i scrierea datelor la nivel de tip primitiv i nu la nivel de octet. Clasele care ofer un astfel de suport implementeaz interfeele DataInput, respectiv DataOutput. Acestea definesc metodele pe care trebuie s le pun la dispoziie n vederea citireii/scrierii datelor de tip primitiv. Cele mai folosite metode, altele dect cele comune tuturor fluxurilor, sunt date n tabelul de mai jos: DataInputStream DataOutputStream readBoolean writeBoolean readByte writeByte readChar writeChar readDouble writeDouble readFloat writeFloat readInt writeInt readLong writeLong readShort writeShort readUTF writeUTF Aceste metode au denumirile generice de readXXX i writeXXX, specificate de interfeele DataInput i DataOutput i pot provoca excepii de tipul IOException. Denumirile lor sunt sugestive pentru tipul de date pe care l prelucreaz, mai puin readUTF i writeUTF care se ocup cu obiecte de tip String, fiind singurul tip referin permis de aceste clase. Scrierea datelor folosind fluxuri de acest tip se face n format binar, ceea ce nseamn c un fiier n care au fost scrise informaii folosind metode writeXXX nu va putea fi citit dect prin metode readXXX. Transformarea unei valori n format binar se numete serializare. Clasele DataInputStream i DataOutputStream permit serializarea tipurilor primitive i a irurilor de caractere. Serializarea celorlalte tipuri referin va fi fcut prin

Note

Programare orientat obiect intermediul altor clase, cum ar fi ObjectInputStream i ObjectOutputStream (vezi Serializarea obiectelor). 2.4.8 Fluxuri standard de intrare i ieire Mergnd pe linia introdus de sistemul de operare UNIX, orice program Java are : o intrare standard o ieire standard o ieire standard pentru erori n general, intrarea standard este tastatura iar ieirea standard este ecranul. Intrarea i ieirea standard sunt reprezentate de obiecte pre-create ce descriu fluxuri de date care comunic cu dispozitivele standard ale sistemului. Aceste obiecte sunt definite publice n clasa System i sunt: System.in - fluxul standard de intrare, de tip InputStream System.out - fluxul standard de ieire, de tip PrintStream System.err - fluxul standard pentru erori, de tip PrintStream a) Afisarea informaiilor pe ecran Am vzut deja numeroase exemple de utilizare a fluxului standard de ieire, el fiind folosit la afiarea oricror rezultate pe ecran (n modul consol): System.out.print (argument); System.out.println(argument); System.out.printf (format, argumente...); System.out.format (format, argumente...); Fluxul standard pentru afiarea erorilor se folosete similar i apare uzual n secvenele de tratare a excepiilor. Implicit, este acelai cu fluxul standard de ieire. catch(Exception e) { System.err.println("Exceptie:" + e); } Fluxurile de ieire pot fi folosite aadar fr probleme deoarece tipul lor este PrintStream, clas concret pentru scrierea datelor. n schimb, fluxul standard de intrare System.out este de tip InputStream, care este o clas abstract, deci pentru a-l putea utiliza eficient va trebui sa-l folosim mpreuna cu un flux de procesare(filtrare) care s permit citirea facil a datelor. b) Citirea datelor de la tastatur Pn la versiunea 1.5, datele se citeau de la tastatur folosind o nlnuire de fluxuri primitive i de procesare. BufferedReader stdin = new BufferedReader (new InputStreamReader(System.in)); System.out.print("Introduceti o linie:"); String linie = stdin.readLine(); Ulterior, linia citit poate suporta conversii n alte tipuri de date. c) Redirectarea fluxurilor standard Redirectarea fluxurilor standard presupune stabilirea unei alte surse dect tastatura pentru citirea datelor, respectiv alte destinaii dect ecranul pentru cele dou fluxuri de ieire. n clasa System exist urmtoarele metode statice care realizeaz acest lucru: setIn(InputStream) - redirectare intrare

67

Note

68

Programare orientat obiect setOut(PrintStream) - redirectare iesire setErr(PrintStream) - redirectare erori Redirectarea ieirii este util n special atunci cnd sunt afiate foarte multe date pe ecran. Putem redirecta afisarea ctre un fiier pe care s-l citim dup execuia programului. Secvena clasic de redirectare a ieirii este ctre un fiier este: PrintStream fis = new PrintStream (new FileOutputStream("rezultate.txt"))); System.setOut(fis); Redirectarea erorilor ntr-un fiier poate fi de asemenea util i se face ntr-o manier similar: PrintStream fis = new PrintStream(new FileOutputStream("erori.txt"))); System.setErr(fis); Redirectarea intrrii poate fi folositoare pentru un program n mod consol care primete mai multe valori de intrare. Pentru a nu le scrie de la tastatur de fiecare dat n timpul testrii programului, ele pot fi puse ntr-un fiier, redirectnd intrarea standard ctre acel fiier. n momentul cnd testarea programului a luat sfrsit redirectarea poate fi eliminat, datele fiind cerute din nou de la tastatur. 2.4.9 Intrri i ieiri formatate Incepnd cu versiunea 1.5, limbajul Java pune la dispoziii modaliti simplificate pentru afiarea formatat a unor informaii, respectiv pentru citirea de date formatate de la tastatur. a) Intrri formatate Clasa java.util.Scanner ofer o soluie simpl pentru formatarea unor informaii citite de pe un flux de intrare fie pe octei, fie pe caractere, sau chiar dintr-un obiect de tip File. Pentru a citi de la tastatur vom specifica ca argument al constructorului fluxul System.in: Scanner s = new Scanner(System.in); Clasa Scanner ofer cte o metod pentru citirea fiecrui tip de date primitiv, de tipul nextTipDate() i metoda next() pentru citirea unui ir de caractere. Exemplu: String nume = s.next(); int varsta = s.nextInt(); double salariu = s.nextDouble(); b) Ieiri formatate Clasele PrintStream i PrintWriter pun la dispoziiile, pe lng metodele print, println care ofereau posibilitatea de a afia un ir de caractere, i metodele format, printf (echivalente) ce permit afiarea formatat a unor variabile. Astfel, cu ajutorul unor specificatori care au forma general: %[argument_index$][flags][lime][.precizie]conversie datele care se tipresc pe ecran pot fi formatate n diverse moduri. Exemplu: System.out.printf("%s %8.2f %2d", nume, salariu, varsta); Pentru mai multe detalii despre formatarea ieirilor se recomand studierea mai n detaliu a clasei java.util.Formatter. Note

Programare orientat obiect Ierarhia claselor ce descriu fluxuri: InputStream o ByteArrayInputStream o FileInputStream o FilterInputStream o BufferedInputStream o DataInputStream (implements java.io.DataInput) o LineNumberInputStream o PushbackInputStream ObjectInputStream PipedInputStream SequenceInputStream StringBufferInputStream o OutputStream ByteArrayOutputStream FileOutputStream FilterOutputStream o BufferedOutputStream o DataOutputStream (implements java.io.DataOutput) o PrintStream ObjectOutputStream PipedOutputStream o Reader BufferedReader o LineNumberReader CharArrayReader FilterReader o PushbackReader InputStreamReader o FileReader PipedReader StringReader o Writer BufferedWriter CharArrayWriter FilterWriter OutputStreamWriter o FileWriter PipedWriter PrintWriter o StringWriter
o

69

Observaie: Clasele scrise cu caractere nclinate reprezint fluxurile primitive. Note

70

Programare orientat obiect 2.4.10 Clasa RandomAccesFile (fiiere cu acces direct) Dup cum am vzut, fluxurile sunt procese secveniale de intrare/ieire. Acestea sunt adecvate pentru lucrul cu medii secveniale de memorare a datelor, cum ar fi banda magnetic sau pentru transmiterea informaiilor prin reea, desi sunt foarte utile i pentru dispozitive n care informaia poate fi accesat direct. Clasa RandomAccesFile are urmtoarele caracteristici: permite accesul nesecvenial (direct) la coninutul unui fiier; este o clas de sine stttoare, subclas direct a clasei Object; se gsete n pachetul java.io; implementeaz interfeele DataInput i DataOutput, ceea ce nseamna ca sunt disponibile metode de tipul readXXX, writeXXX, ntocmai ca la clasele DataInputStream i DataOutputStream; permite att citirea ct i scriere din/in fiiere cu acces direct; permite specificarea modului de acces al unui fiier (read-only, readwrite). Constructorii acestei clase sunt: RandomAccessFile(String numeFisier, String modAcces) IOException RandomAccessFile(String numeFisier, String modAcces) IOException unde modAcces poate fi: r - fiierul este deschis numai pentru citire (read-only) rw - fiierul este deschis pentru citire i scriere (read-write)

throws throws

Exemple: RandomAccesFile f1 = new RandomAccessFile("fisier.txt", "r"); //deschide un fisier pentru citire RandomAccesFile f2 = new RandomAccessFile("fisier.txt", "rw"); //deschide un fisier pentru scriere si citire Clasa RandomAccesFile suport noiunea de pointer de fiier. Acesta este un indicator ce specific poziia curent n fiier. La deschiderea unui fiier pointerul are valoarea 0, indicnd nceputul fiierului. Apeluri la metodele de citire/scrirere deplaseaz pointerul fiierului cu numrul de octei citii sau scrii de metodele respective. n plus fa de metodele de tip read i write clasa pune la dispozitie i metode pentru controlul poziiei pointerului de fiier. Acestea sunt: skipBytes - mut pointerul fiierului nainte cu un numr specificat de octei seek - poziioneaza pointerului fiierului naintea unui octet specificat getFilePointer - returneaz poziia pointerului de fiier. Metodele mai importante ale clasei RandomAccesFile:
void close() nchide fiierul i elibereaz eventualele resurse sistem asociate lui. long getFilePointer() Returneaz poziia curent a pointerului (cursorului) de fiier. long length() Returneaz dimensiunea fiierului (n octei). int read() Citete un octet din fiier.

Note

Programare orientat obiect


int read(byte[] b) Citete pn la b.length octei din fiier i i depune n vectorul b. boolean readBoolean() Citete un boolean din fiier. byte readByte() Citete un byte din fiier. char readChar() Citete a caracter din fiier. double readDouble() Citete un double din fiier. float readFloat() Citete un float din fiier.

71

void readFully(byte[] b) Citete b.length octei din fiier n vectorul b, ncepnd de la poziia curent din fiier. int readInt() Citete un int din fiier. String readLine() Citete o linie ntreag de text din fiier. long readLong() Citete un long din fiier. short readShort() Citete un short din fiier. String readUTF() Citete un ir de caractere din fiier. void seek(long pos) Poziioneaz pointerul de fiier pe cel de-al pos octet din fiier. void setLength(long newLength) Seteaz o nou dimensiune (n octei) pentru fiier. int skipBytes(int n) ncearc s poziioneze pointerul de fiier peste n octei fa de poziia sa curent. void write(byte[] b) Scrie b.length octei din vectorul b n fiier, ncepnd cu poziia curent din fiier. void writeBoolean(boolean v) Scrie un boolean n fiier sub forma unei valori de 1 octet. void writeByte(int v) Scrie a byte n fiier sub forma unei valori de 1 octet. void writeBytes(String s) Scrie irul de caractere s n fiier sub forma unei secvene de octei. void writeChar(int v) Scrie un char n fiier sub forma unei valori de 2 octei. void writeChars(String s) Scrie irul de caractere s n fiier sub forma unei secvene de caractere.

Note

72

Programare orientat obiect


void writeDouble(double v) Convertete valoarea de tip double v n long i scrie valoarea obinut n fiier sub forma unei secvene pe 8 octei. void writeFloat(float v) Convertete valoarea de tip float v n int i scrie valoarea obinut n fiier sub forma unei secvene pe 4 octei. void writeInt(int v) Scrie un int n fiier sub forma unei secvene de 4 octei. void writeLong(long v) Scrie un long n fiier sub forma unei secvene de 8 octei. void writeShort(int v) Scrie un short n fiier sub forma unei secvene de 2 octei. void writeUTF(String str) Scrie n fiier un ir de caractere folosind codificarea independent de platform UTF-8.

2.4.11 Clasa File Clasa File nu se refer doar la un fiier ci poate reprezenta fie un fiier anume, fie multimea fiierelor dintr-un director. Specificarea unui fiier/director se face prin specificarea cii absolute spre acel fiier sau a cii relative fa de directorul curent. Acestea trebuie s respecte conveniile de specificare ale cilor i numelor fiierelor de pe platforma de lucru. Utilitate clasei File const n furnizarea unei modaliti de a abstractiza dependenele cailor i numelor fiierelor fa de maina gazd, precum i punerea la dispoziie a unor metode pentru lucrul cu fisiere i directoare la nivelul sistemului de operare. Astfel, n aceast clas vom gsi metode pentru testarea existenei, tergerea, redenumirea unui fiier sau director, crearea unui director, listarea fiierelor dintr-un director, etc. Trebuie menionat i faptul c majoritatea constructorilor fluxurilor care permit accesul la fiiere accept ca argument un obiect de tip File n locul unui ir ce reprezint numele fiierului respectiv. File f = new File("fisier.txt"); FileInputStream in = new FileInputStream(f); Cel mai uzual constructor al clasei File este: public File(String numeFisier) Metodele mai importante ale clasei File:
boolean canRead() Testeaz dac aplicaia poate citi din fiier. boolean canWrite() Testeaz dac aplicatia poate modifica (scrie) fiierul. boolean createNewFile() Creaz un nou fiier, gol, ns numai dac acesta nu exist deja. boolean delete() terge fiierul curent. boolean exists() Testeaz dac fiierul exist.

Note

String getAbsolutePath()

Programare orientat obiect


Returneaz un ir cu calea absolut spre obiectul curent. String getName() Returneaz numele obiectului curent.

73

String getParent() Returneaz directorul printe al obiectului curent, sau null dac nu exist. boolean isDirectory() Testeaz dac obiectul curent este director. boolean isFile() Testeaz dac obiectul curent este fiier. boolean isHidden() Testeaz dac obiectul curent este un fiier ascuns. long lastModified() Returneaz data ultimei modificri a fiierului (n secunde). long length() Returneaz dimensiunea fiierului (n octei). String[] list() Returneaz un vector de tip String care conine toate fiierele i subdirectoarele obiectului curent. File[] listFiles() Returneaz un vector de tip File care conine toate fiierele i subdirectoarele obiectului curent. boolean mkdir() Creaz un director nou cu numele asociat obiectului curent. boolean renameTo(File dest) Redenumete obiectul curent n dest. boolean setReadOnly() Seteaz obiectul curent ca Read-Only (permite doar operaia de citire).

Test de autoevaluare: 1. Care este diferena dintre un flux primitiv i unul de procesare?

2. Care este avantajului citirii/scrierii cu buffer dect fr buffer?

3. Care sunt fluxurile standard de intrare/ieire?

Note

74

Programare orientat obiect

4. Dai un exemplu de citire de la tastatur a diverse tipuri de date, folosind clasa Scanner.

5. Care este diferena dintre clasele File i RandomAccessFile din punct de vedere al operaiilor asupra fiierelor?

Bibliografie : 1. Cristian Frsinaru Curs practic de Java 2. Bruce Eckel Thinking in Java 4th Edition, Ed. Prentice Hall, 2006, ISBN 0-13-187248-6 3. P. Niemeyer, J. Knudsen - Learning Java 3rd Edition, Ed. OReilly, 2005 4. .Tanas,.Andrei,C. Olaru Java de la 0 la expert, Ed.Polirom, 2007, ISBN 978-973-46-0317-6 5. D.Danciu, G.Mardale - Arta programrii n JAVA (Vol. I) Elemente-suport fundamentale, Ed. Albastr, 2005 Note

Programare orientat obiect 2.5 Colecii

75

Obiective: Cunoaterea no terea noiunii de colecie si utilitatea folosirii ei Cunoaterea principalelor tipuri de colec terea colecii Cunoaterea metodelor care pot fi aplicate coleciilor terea Cunoaterea modalit terea modalitilor de parcurgere a coleciilor

2.5.1 Introducere O colecie este un obiect care grupeaz mai multe elemente ntr-o singur ie grupeaz o singur unitate. Prin intermediul coleciilor vom avea acces la diferite tipuri de date cum coleciilor ar fi vectori, liste nlnuite, stive, mul imi matematice, tabele de dispersie, etc. uite, mulimi Coleciile sunt folosite att pentru memorarea i manipularea datelor, ct i iile i pentru transmiterea unor informa de la o metod la alta. informaii Tipul de date al elementelor dintr colecie este Object, ceea ce nseamn dintr-o , nseamn c mulimile reprezentate sunt eterogene, putnd include obiecte de orice tip. imile Incepnd cu versiunea 1.2, n Java colec coleciile sunt tratate ntr-o manier o manier unitar, fiind organizate ntr-o arhitectur foarte eficient i flexibil ce cuprinde: o arhitectur Interfee: tipuri abstracte de date ce descriu colec : coleciile i permit utilizarea lor i independent de detaliile implement implementrilor. Implementri: implementri concrete ale interfeelor ce descriu colecii. Aceste ri ii. clase reprezint tipuri de date reutilizabile. Algoritmi: metode care efectueaz diverse operaii utile cum ar fi cutarea sau : efectueaz utarea sortarea, definite pentru obiecte ce implementeaz interfeele ce descriu colec implementeaz ele colecii. Aceti algoritmi se numesc i polimorfici deoarece pot fi folosii pe implement i implementri diferite ale unei colecii, reprezentnd elementul de func ionalitate reutilizabil ii, funcionalitate reutilizabil. Utilizarea coleciilor ofer avantaje evidente n procesul de dezvoltare a iilor ofer unei aplicaii. Cele mai importante sunt: ii. Reducerea efortului de programare: prin punerea la dispozi programatorului a dispoziia torului unui set de tipuri de date i algoritmi ce modeleaz structuri i opera des modeleaz i operaii folosite n aplicaii. Creterea vitezei i calitii programului: implement rile efective ale colec ii implementrile coleciilor sunt de nalt performan i folosesc algoritmi cu timp d lucru optim. de Astfel, la scrierea unei aplica putem s ne concentrm eforturile asupra aplicaii m problemei n sine i nu asupra modului de reprezentare i manipulare a i i informaiilor. 2.5.2 Interfee ce descriu colec e colecii Collection - List - Set - SortedSet Map - SortedMap Note

76

Programare orientat obiect Interfeele reprezint nucleul mecanismului de lucru cu colecii, scopul lor fiind de a permite utilizarea structurilor de date independent de modul lor de implementare. Collection modeleaz o colecie la nivelul cel mai general, descriind un grup de obiecte numite i elementele sale. Unele implementri ale acestei interfee permit existena elementelor duplicate, alte implementri nu. Unele au elementele ordonate, altele nu. Platforma Java nu ofer nici o implementare direct a acestei interfee, ci exist doar implementri ale unor subinterfee mai concrete, cum ar fi Set sau List. Interfata Collection: public interface Collection { // Metode cu caracter general int size(); boolean isEmpty(); void clear(); Iterator iterator(); // Operatii la nivel de element boolean contains(Object element); boolean add(Object element); boolean remove(Object element); // Operatii la nivel de multime boolean containsAll(Collection c); boolean addAll(Collection c); boolean removeAll(Collection c); boolean retainAll(Collection c); // Metode de conversie in vector Object[] toArray(); Object[] toArray(Object a[]); } Set modeleaz noiunea de mulime n sens matematic. O mulime nu poate avea elemente duplicate, mai bine zis nu poate conine dou obiecte o1 i o2 cu proprietatea o1.equals(o2). Motenete metodele din Collection, fr a avea alte metode specifice. Dou dintre clasele standard care ofer implementri concrete ale acestei interfee sunt HashSet i TreeSet. SortedSet este asemntoare cu interfaa Set, diferena principal constnd n faptul c elementele dintr-o astfel de colecie sunt ordonate ascendent. Pune la dispoziie operaii care beneficiaz de avantajul ordonrii elementelor. Ordonarea elementelor se face conform ordinii lor naturale, sau conform cu ordinea dat de un comparator specificat la crearea coleciei i este meninut automat la orice operaie efectuat asupra mulimii. Singura condiie este ca, pentru orice dou obiecte o1, o2 ale coleciei, apelul o1.compareTo(o2) (sau comparator.compare(o1, o2), dac este folosit un comparator) trebuie s fie valid i s nu provoace excepii. Fiind subclas a interfeei Set, motenete metodele acesteia, oferind metode suplimentare ce in cont de faptul c mulimea este sortat: public interface SortedSet extends Set { // Subliste SortedSet subSet(Object fromElement, Object toElement);

Note

Programare orientat obiect SortedSet headSet(Object toElement); SortedSet tailSet(Object fromElement); // Capete Object first(); Object last(); Comparator comparator(); } Clasa care implementeaz aceast interfa este TreeSet. List descrie liste (secvene) de elemente indexate. Listele pot contine duplicate i permit un control precis asupra poziiei unui element prin intermediul indexului acelui element. n plus, fa de metodele definite de interfaa Collection, avem metode pentru acces poziional, cutare i iterare avansat. Definiia interfeei este: public interface List extends Collection { // Acces pozitional Object get(int index); Object set(int index, Object element); void add(int index, Object element); Object remove(int index); abstract boolean addAll(int index, Collection c); // Cautare int indexOf(Object o); int lastIndexOf(Object o); // Iterare ListIterator listIterator(); ListIterator listIterator(int index); // Extragere sublista List subList(int from, int to); } Clase standard care implementeaz aceast interfa sunt: ArrayList, LinkedList, Vector. Map descrie structuri de date ce asociaz fiecarui element o cheie unic, dup care poate fi regsit. Obiectele de acest tip nu pot conine chei duplicate i fiecare cheie este asociat la un singur element. Ierarhia interfeelor derivate din Map este independent de ierarhia derivat din Collection. Definiia interfeei este prezentat mai jos: public interface Map { // Metode cu caracter general int size(); boolean isEmpty(); void clear(); // Operatii la nivel de element Object put(Object key, Object value); Object get(Object key); Object remove(Object key); boolean containsKey(Object key); boolean containsValue(Object value); // Operatii la nivel de multime void putAll(Map t); // Vizualizari ale colectiei

77

Note

78

Programare orientat obiect public Set keySet(); public Collection values(); public Set entrySet(); // Interfata pentru manipularea unei inregistrari public interface Entry { Object getKey(); Object getValue(); Object setValue(Object value); } } Clase care implementeaz interfaa Map sunt HashMap, TreeMap i Hashtable. SortedMap este asemntoare cu interfaa Map, la care se adaug faptul c mulimea cheilor dintr-o astfel de colecie este meninut ordonat ascendent conform ordinii naturale, sau conform cu ordinea dat de un comparator specificat la crearea coleciei. Este subclasa a interfeei Map, oferind metode suplimentare pentru: extragere de subtabele, aflarea primei/ultimei chei, aflarea comparatorului folosit pentru ordonare. Definiia interfeei este dat mai jos: public interface SortedMap extends Map { // Extragerea de subtabele SortedMap subMap(Object fromKey, Object toKey); SortedMap headMap(Object toKey); SortedMap tailMap(Object fromKey); // Capete Object first(); Object last(); // Comparatorul folosit pentru ordonare Comparator comparator(); } Clasa care implementeaz aceast interfa este TreeMap. 2.5.3 Implementri ale coleciilor Pe lng organizarea ierarhic a interfeelor implementate, clasele ce descriu colecii sunt de asemenea concepute ntr-o manier ierarhic, ca n schia de mai jos: class AbstractCollection (implements Collection)
o

class AbstractList (implements List) o class AbstractSequentialList o class LinkedList (implements List) class ArrayList (implements List) class Vector (implements List) o class Stack class AbstractSet (implements Set) class HashSet (implements Set) o class LinkedHashSet (implements Set) class TreeSet (implements SortedSet)

class AbstractMap (implements Map) Note


o

class HashMap (implements Map)

Programare orientat obiect


o class LinkedHashMap class TreeMap (implements SortedMap)

79

nainte de versiunea 1.2, exista un set de clase pentru lucrul cu colecii, ns acestea nu erau organizate pe ierarhia de interfee prezentat n seciunea anterioar. Aceste clase sunt n continuare disponibile i multe dintre ele au fost adaptate n aa fel nct s se integreze n noua abordare. Pe lng acestea au fost create noi clase corespunztoare interfeelor definite, chiar dac funcionalitatea lor era aproape identic cu cea a unei clase anterioare. Clasele de baz care implementeaz interfee ce descriu colecii au numele de forma <Implementare> <Interfata>, unde implementare se refer la structura intern folosit pentru reprezentarea mulimii, i sunt prezentate n tabelul de mai jos, mpreun cu interfeele corespunztoare (clasele din vechiul model sunt trecute pe rndul de jos): Interfaa Set SortedSet List Map SortedMap Clasa HashSet TreeSet ArrayList, LinkedList, Vector HashMap, Hashtable TreeMap

Aadar se observ existena unor clase care ofer aceeai funcionalite, cum ar fi ArrayList i Vector, HashMap i Hashtable. Evident, implementarea interfeelor este explicit realizat la nivelul superclaselor abstracte, acestea oferind de altfel i implementri concrete pentru multe din metodele definite de interfee. n general, clasele care descriu colecii au unele trsaturi comune, cum ar fi: permit elementul null, sunt serializabile, au definit metoda clone, au definit metoda toString,care returneaz o reprezentare ca ir de caractere a coleciei respective, permit crearea de iteratori pentru parcurgere, au att constructor fr argumente ct i un constructor care accept ca argument o alt colecie exceptnd clasele din arhitectura veche, nu sunt sincronizate. 2.5.4 Folosirea eficient a coleciilor Dup cum am vazut, fiecare interfa ce descrie o colecie are mai multe implementri. De exemplu, interfaa List este implementat de clasele ArrayList i LinkedList, prima fiind n general mult mai folosit. De ce exist atunci i clasa LinkedList? Raspunsul const n faptul c folosind reprezentri diferite ale mulimii gestionate putem obine performante mai bune n funcie de situaie, prin realizarea unor compromisuri ntre spaiul necesar pentru memorarea datelor, rapiditatea regsirii acestora i timpul necesar actualizrii coleciei n cazul unor modificri. n urma testarii timpilor de rulare s-a putut constata ca pentru clasele ArrayList i LinkedList, adugarea elementelor este rapid pentru ambele tipuri de liste.

Note

80

Programare orientat obiect ArrayList ofer acces n timp constant la elementele sale i din acest motiv folosirea lui get este rapid, n timp ce pentru LinkedList este extrem de lent, deoarece ntr-o list nlanuit accesul la un element se face prin parcurgerea secvenial a listei pn la elementul respectiv. La operaiunea de eliminare, folosirea lui ArrayList este lent deoarece elementele rmase sufer un proces de reindexare (shift la stnga), n timp ce pentru LinkedList este rapid i se face prin simpla schimbare a unei legturi. Deci, ArrayList se comport bine pentru cazuri n care avem nevoie de regsirea unor elemente la poziii diferite n list, iar LinkedList funcioneaza eficient atunci cnd facem multe operaii de modificare (tergeri, inserri). Concluzia nu este c una din aceste clase este mai bun dect cealalt, ci c exist diferene substaniale n reprezentarea i comportamentul diferitelor implementri i c alegerea unei anumite clase pentru reprezentarea unei mulimi de elemente trebuie s se fac n funcie de natura problemei ce trebuie rezolvat. 2.5.5 Algoritmi polimorfici Algoritmii polimorfici descrii n aceast seciune sunt metode definite n clasa Collections care permit efectuarea unor operaii utile cum ar fi cutarea, sortarea, etc. Caracterisiticile principale ale acestor algoritmi sunt: sunt metode de clas (statice); au un singur argument de tip colecie; apelul lor general va fi de forma: Collections.algoritm(colectie, [argumente]); majoritatea opereaz pe liste dar i pe colecii arbitrare. Metodele mai des folosite din clasa Collections sunt: sort - sorteaz ascendent o list referitor la ordinea s natural sau la ordinea dat de un comparator; shuffle - amestec elementele unei liste - opusul lui sort; binarySearch - efectueaz cutarea eficient (binar) a unui element ntr-o list ordonat; reverse - inverseaz ordinea elementelor dintr-o list; fill - populeaza o lista cu un anumit element repetat de un numr de ori; copy - copie elementele unei liste n alta; min - returneaz minimul dintr-o colecie; max - returneaz maximul dintr-o colecie; swap - interschimb elementele de la dou poziii specificate ale unei liste; enumeration - returneaza o enumerare a elementelor dintr-o colecie; unmodifiableTipColectie - returneaz o instan care nu poate fi modificat a coleciei respective; synchronizedTipColectie - returneaz o instan sincronizat a unei colecii. 2.5.6 Tipuri generice Tipurile generice, introduse n versiunea 1.5 a limbajului Java, simplific lucrul cu colecii, permind tipizarea elementelor acestora. Definirea unui tip generic se realizeaz prin specificarea ntre paranteze unghiulare a unui tip de date Java, efectul fiind impunerea tipului respectiv pentru toate elementele coleciei: <TipDate>. S considerm un exemplu de utilizare a coleciilor nainte i dup introducerea tipurilor generice:

Note

Programare orientat obiect // Inainte de 1.5 ArrayList list = new ArrayList(); list.add(new Integer(123)); int val = ((Integer)list.get(0)).intValue(); n exemplul de mai sus, lista definit poate conine obiecte de orice tip, dei am dori ca elementele s fie doar numere ntregi. Mai mult, trebuie s facem cast explicit de la tipul Object la Integer atunci cnd prelum valoarea unui element. Folosind tipuri generice, putem rescrie secvena astfel: // Dup 1.5, folosind tipuri generice ArrayList<Integer> list = new ArrayList<Integer>(); list.add(new Integer(123)); int val = list.get(0).intValue(); Dac utilizm i mecanismul de autoboxing, obinem o variant mult simplificat a secvenei iniiale: // Dup 1.5, folosind si autoboxing ArrayList<Integer> list = new ArrayList<Integer>(); list.add(123); int val = list.get(0); n cazul folosirii tipurilor generice, ncercarea de a utiliza n cadrul unei colecii a unui element necorespunztor ca tip va produce o eroare la compilare, spre deosebire de varianta anterioar ce permitea doara aruncarea unor excepie de tipul ClassCastException n cazul folosirii incorecte a tipurilor. 2.5.7 Iteratori i enumerri Enumerrile i iteratorii descriu modaliti pentru parcurgerea secvenial a unei colecii, indiferent dac aceasta este indexat sau nu. Ei sunt descrii de obiecte ce implementeaz interfeele Enumeration, respectiv Iterator sau ListIterator. Toate clasele care implementeaz colecii au metode ce returneaz o enumerare sau un iterator pentru parcurgerea elementelor lor. Deoarece funcionalitatea interfeei Enumeration se regsete n Iterator, aceasta din urm este preferat n noile implementri ale coleciilor. Metodele uzuale ale acestor interfee sunt prezentate mai jos, mpreun cu modalitatea lor de folosire, semnificaiile lor fiind evidente: Enumeration: hasMoreElements, nextElement // Parcurgerea elementelor unui vector v Enumeration e = v.elements; while (e.hasMoreElements()) { System.out.println(e.nextElement()); } // sau, varianta mai concisa for (Enumeration e = v.elements(); e.hasMoreElements();) { System.out.println(e.nextElement()); } Iterator: hasNext, next, remove // Parcurgerea elementelor unui vector si eliminarea elementelor nule for (Iterator it = v.iterator(); it.hasNext();) { Object obj = it.next(); if (obj == null) it.remove();

81

Note

82

Programare orientat obiect } ListIterator: hasNext, hasPrevious, next, previous, remove, add, set // Parcurgerea elementelor unui vector si inlocuirea elementelor nule cu 0 for (ListIterator it = v.listIterator(); it.hasNext(); ) { Object obj = it.next(); if (obj == null) it.set(new Integer(0)); } Iteratorii simpli permit eliminarea elementului curent din colecia pe care o parcurg, cei de tip ListIterator permit i inserarea unui element la poziia curent, respectiv modificarea elementului curent, precum i iterarea n ambele sensuri. Iteratorii sunt preferai enumerrilor datorit posibilitii lor de a aciona asupra coleciei pe care o parcurg prin metode de tip remove, add, set dar i prin faptul c denumirile metodelor sunt mai concise. Atenie! Deoarece coleciile sunt construite peste tipul de date Object, metodele de tip next sau prev ale iteratorilor vor returna tipul Object, fiind responsabilitatea noastr de a face conversie (cast) la alte tipuri de date, dac este cazul. Incepnd cu versiunea 1.5 a limbajului Java, exist o variant simplificat de utilizare a iteratorilor. Astfel, o secven de genul: ArrayList<Integer> list = new ArrayList<Integer>(); for (Iterator i = list.iterator(); i.hasNext(); ) { Integer val=(Integer)i.next(); // Proceseaza val ... } poate fi rescris astfel: ArrayList<Integer> list = new ArrayList<Integer>(); for (Integer val : list) { // Proceseaza val ... }

1.

Test de autoevaluare: Cte tipuri de date pot exista ntr-o colecie la un momentdat?

2.

Care este diferena dintre clasele List i Set?

Note

Programare orientat obiect

83

3. Creai o colecie de tip list i efectuai asupra ei o cte o operaie de adugare i una de tergere.

4. Care este utilitatea folosirii tipurilor generice?

5. Dai un exemplu de parcurgere a unei colecii folosind unul din iteratorii prezentai.

Note

84

Programare orientat obiect Bibliografie : 1. Cristian Frsinaru Curs practic de Java 2. Bruce Eckel Thinking in Java 4th Edition, Ed. Prentice Hall, 2006, ISBN 0-13-187248-6 3. P. Niemeyer, J. Knudsen - Learning Java 3rd Edition, Ed. OReilly, 2005 4. .Tanas,.Andrei,C. Olaru Java de la 0 la expert, Ed.Polirom, 2007, ISBN 978-973-46-0317-6 5. D.Danciu, G.Mardale - Arta programrii n JAVA (Vol. I) Elemente-suport fundamentale, Ed. Albastr, 2005

Note

Programare orientat obiect

85

Note

86

Programare orientat obiect III. Operatii speciale asupra claselor si obiectelor 3.1 Serializarea obiectelor

Obiective: Cunoaterea noiunilor de serializare/deserializare i utilitatea iunilor lor Cunoaterea fluxurilor necesare pentru realizarea opera terea operaiilor de serializare/deserializare deserializare Cunoaterea posibilit terea posibilitilor de personalizare a serializrii

3.1.1 Folosirea serializrii Definiie: Serializarea este o metod ce permite transformarea unui obiect ntr ntr-o secven de octe sau caractere din care s poat fi refcut ulterior obiectul octei cut original. Cu alte cuvinte, serializarea permite salvarea ntr o manier unitar a ntr-o manier tuturor informaiilor unui obiect pe un mediu de stocare extern programului. pe Procesul invers, de citire a unui obiect serializat pentru a reface starea a-i original, se nume , numete deserializare. ntr-un cadru mai larg, prin serializare se un ntelege procesul de scriere/citire a obiectelor. Tipurile primitive pot fi de asemenea serializate. le Utilitatea serializarii const n urmtoarele aspecte: const Asigur un mecanism simplu de utilizat pentru salvarea i restaurarea a datelor. Permite persisten obiectelor, ceea ce nseamna c durata de via a unui persistena viaa obiect nu este determinat de execuia unui programn care acesta este definit determinat ia obiectul poate exista i ntre apelurile programelor care l folosesc. Acest lucru i se realizeaz prin serializarea obiectului i scrierea lui pe disc nainte de i terminarea unui program, apoi, la relansarea programului, obiectul va fi citit de a pe disc i starea lui refacut Acest tip de persisten a obiectelor se nume i refacut. numete persisten uoar ntruct ea trebuie efectuat explicit de c programator i oar, ctre nu este realizat a automat de ctre sistem. Compensarea diferen diferenelor ntre sisteme de operare - transmiterea unor informaii ntre platforme de lucru diferite se realizeaz unitar, independent de ii realizeaz formatul de reprezentare a datelor, ordinea octe ilor sau alte detalii specifi octeilor specifice sistemelor repective. Transmiterea datelor n re reea - Aplicaiile ce ruleaz n re reea pot comunica ntre ele folosind fluxuri pe care sunt trimise, respectiv recep recepionate obiecte serializate. RMI (Remote Method Invocation) - este o modalitate prin c care metodele unor obiecte de pe o alt main pot fi apelate ca i cum acestea ar exista local pe alt i maina pe care ruleaz aplicaia. Atunci cnd este trimis un mesaj c ina ruleaz ctre un obiect remote (de pe alt main), serializarea este utilizat pentru transportul alt ), argumentelor prin re i pentru returnarea valorilor. reea Java Beans - sunt componente reutilizabile, de sine st toare ce pot fi utilizate stttoare n medii vizuale de dezvoltare a aplica aplicaiilor. Orice component Bean are o stare component definit de valorile implicite a proprietilor sale, stare care este specificat n ale ilor specificat etapa de design a aplica iei. Mediile vizuale folosesc mecanismul serializ aplicaiei. serializrii pentru asigurarea persisten componentelor Bean. persistenei

Note

Programare orientat obiect Un aspect important al serializrii este c nu salveaz doar imaginea unui obiect ci i toate referinele la alte obiecte pe care acesta le conine. Acesta este un proces recusiv de salvare a datelor, ntruct celelalte obiectele referite de obiectul care se serializeaz pot referi la rndul lor alte obiecte, i aa mai departe. Aadar referinele care construiesc starea unui obiect formeaz o ntreag reea, ceea ce nseamn c un algoritm general de salvare a strii unui obiect nu este tocmai facil. n cazul n care starea unui obiect este format doar din valori ale unor variabile de tip primitiv, atunci salvarea informaiilor ncapsulate n acel obiect se poate face i prin salvarea pe rnd a datelor, folosind clasa DataOutputStream, pentru ca apoi s fie restaurate prin metode ale clasei DataInputStream, dar, aa cum am vazut, o asemenea abordare nu este n general suficient, deoarece pot aprea probleme cum ar fi: variabilele membre ale obiectului pot fi instane ale altor obiecte, unele cmpuri pot face referin la acelai obiect, etc. Serializarea n format binar a tipurilor primitive i a obiectelor se realizeaz prin intermediul fluxurilor definite de clase specializate n acest scop cu ar fi: ObjectOutputStream pentru scriere i ObjectInputStream pentru restaurare. n continuare, prin termenul serializare ne vom referi doar la serializarea n format binar. a) Serializarea tipurilor primitive Serializarea tipurilor primitive poate fi realizat fie prin intermediul fluxurilor DataOutputStream i DataInputStream, fie cu ObjectOutputStream i ObjectInputStream. Acestea implementeaz interfeele DataInput, respectiv DataOutput ce declar metode de tipul readTipPrimitiv, respectiv writeTipPrimitiv pentru scrierea/citirea datelor primitive i a irurilor de caractere. Mai jos este prezentat un exemplu de serializare folosind clasa DataOutputStream: FileOutputStream fos = new FileOutputStream("test.dat"); DataOutputStream out = new DataOutputStream(fos); out.writeInt(12345); out.writeDouble(12.345); out.writeBoolean(true); out.writeUTF("Sir de caractere"); out.flush(); fos.close(); Citirea informaiilor scrise n exemplul de mai sus se va face astfel: FileInputStream fis = new FileInputStream("test.dat"); DataInputStream in = new DataInputStream(fis); int i = in.readInt(); double d = in.readDouble(); boolean b = in.readBoolean(); String s = in.readUTF(); fis.close(); b) Serializarea obiectelor Serializarea obiectelor se realizeaz prin intermediul fluxurilor definite de clasele ObjectOutputStream (pentru salvare) i ObjectInputStream (pentru restaurare). Acestea sunt fluxuri de procesare, ceea ce nseamna c vor fi folosite Note

87

88

Programare orientat obiect mpreuna cu alte fluxuri pentru scrierea/citirea efectiv a datelor pe mediul extern pe care va fi salvat, sau de pe care va fi restaurat un obiect serializat. Mecanismul implicit de serializare a unui obiect va salva numele clasei obiectului, signatura clasei i valorile tuturor cmpurile serializabile ale obiectului. Referinele la alte obiecte serializabile din cadrul obiectului curent vor duce automat la serializarea acestora iar referinele multiple ctre un acelai obiect sunt codificate utiliznd un algoritm care s poat reface reeaua de obiecte la aceeai stare ca atunci cnd obiectul original a fost salvat. Clasele ObjectInputStream i ObjectOutputStream implementeaz interfeele ObjectInput, respectiv ObjectOutput care extind DataInput, respectiv DataOutput, ceea ce nseamn c, pe lng metodele dedicate serializrii obiectelor, vor exista i metode pentru scrierea/citirea datelor primitive i a irurilor de caractere. Metodele pentru serializarea obiectelor sunt: writeObject, pentru scriere i readObject, pentru restaurare. c) Clasa ObjectOutputStream Scrierea obiectelor pe un flux de ieire este un proces extrem de simplu, secvena uzual fiind cea de mai jos: ObjectOutputStream out = new ObjectOutputStream(fluxPrimitiv); out.writeObject(referintaObiect); out.flush(); fluxPrimitiv.close(); Exemplul de mai jos construiete un obiect de tip Date i l salveaz n fiierul test.ser, mpreun cu un obiect de tip String. Evident, fiierul rezultat va conine informaiile reprezentate n format binar. FileOutputStream fos = new FileOutputStream("test.ser"); ObjectOutputStream out = new ObjectOutputStream(fos); out.writeObject("Ora curenta:"); out.writeObject(new Date()); out.flush(); fos.close(); Deoarece implementeaz interfaa DataOutput, pe lnga metoda de scriere a obiectelor, clasa pune la dispozitie i metode de tipul writeTipPrimitiv pentru serializarea tipurilor de date primitive i a irurilor de caractere, astfel nct apeluri ca cele de mai jos sunt permise : out.writeInt(12345); out.writeDouble(12.345); out.writeBoolean(true); out.writeUTF("Sir de caractere"); Metoda writeObject arunc excepii de tipul IOException i derivate din aceasta, mai precis NotSerializableException dac obiectul primit ca argument nu este serializabil, sau InvalidClassException dac sunt probleme cu o clas necesar n procesul de serializare. Vom vedea n continuare c un obiect este serializabil dac este instan a unei clase ce implementeaz interfaa Serializable. Note

Programare orientat obiect d) Clasa ObjectInputStream Odat ce au fost scrise obiecte i tipuri primitive de date pe un flux, citirea acestora i reconstruirea obiectelor salvate se va face printr-un flux de intrare de tip ObjectInputStream. Acesta este de asemenea un flux de procesare i va trebui asociat cu un flux pentru citirea efectiv a datelor, cum ar fi FileInputStream pentru date salvate ntr-un fiier. Secvena uzual pentru deserializare este cea de mai jos: ObjectInputStream in = new ObjectInputStream(fluxPrimitiv); Object obj = in.readObject(); //sau TipReferinta ref = (TipReferinta)in.readObject(); fluxPrimitiv.close(); Citirea informaiilor scrise n exemplul de mai sus se va face astfel: FileInputStream fis = new FileInputStream("test.ser"); ObjectInputStream in = new ObjectInputStream(fis); String mesaj = (String)in.readObject(); Date data = (Date)in.readObject(); fis.close(); Trebuie observat c metoda readObject are tipul returnat Object, ceea ce nseamn c trebuie realizat explicit conversia la tipul corespunzator obiectului citit: Date date = in.readObject(); // gresit Date date = (Date)in.readObject(); // corect Atenie! Ca i la celelalte fluxuri de date care implemeteaz interfaa DataInput citirea dintr-un flux de obiecte trebuie s se fac exact n ordinea n care acestea au fost scrise, altfel vor aprea evident excepii n procesul de deserializare. Clasa ObjectInputStream implementeaz interfaa DataInput deci, pe lng metoda de citire a obiectelor, clasa pune la dispoziie i metode de tipul readTipPrimitiv pentru citirea tipurilor de date primitive i a irurilor de caractere. int i = in.readInt(); double d = in.readDouble(); boolean b = in.readBoolean(); String s = in.readUTF(); 3.1.2 Obiecte serializabile Un obiect este serializabil dac i numai dac clasa din care face parte implementeaz interfaa Serializable. Aadar, dac dorim ca instanele unei clase s poat fi serializate, clasa respectiv trebuie s implementeze, direct sau indirect, interfaa Serializable. a) Implementarea interfeei Serializable Interfaa Serializable nu conine nici o declaraie de metod sau constant, singurul ei scop fiind de a identifica clasele ale cror obiecte sunt serializabile. Definiia sa complet este: package java.io; public interface Serializable { // Nimic ! } Declararea claselor ale cror instane trebuie s fie serializate este aadar extrem de simpl, fiind fcut prin simpla implementare a interfeei Serializable:

89

Note

90

Programare orientat obiect public class ClasaSerializabila implements Serializable { // Corpul clasei } Orice subclas a unei clase serializabile este la rndul ei serializabil, ntruct implementeaz indirect interfaa Serializable. n situaia n care dorim s declarm o clas serializabil dar superclasa sa nu este serializabil, atunci trebuie s avem n vedere urmtoarele lucruri: Variabilele accesibile ale superclasei nu vor fi serializate, fiind responsabilitatea clasei curente de a asigura un mecanism propriu pentru salvarea/restaurarea lor. Acest lucru va fi discutat n seciunea referitoare la personalizarea serializrii. Superclasa trebuie s aib obligatoriu un constructor accesibil fr argumente, acesta fiind utilizat pentru iniializarea variabilelor motenite n procesul de restaurare al unui obiect. Variabilele proprii vor fi iniializate cu valorile de pe fluxul de intrare. n lipsa unui constructor accesibil fr argumente pentru superclas, va fi generat o excepie la execuie. n procesul serializrii, dac este ntlnit un obiect care nu implementeaz interfaa Serializable atunci va fi generat o excepie de tipul NotSerializableException ce va identifica respectiva clas neserializabil. b) Controlul serializrii Exist cazuri cnd dorim ca unele variabile membre ale unui obiect s nu fie salvate automat n procesul de serializare. Acestea sunt cazuri comune atunci cnd respectivele cmpuri reprezint informaii confideniale, cum ar fi parole, sau variabile temporare pe care nu are rost s le salvm. Chiar declarate private n cadrul clasei aceste cmpuri particip la serializare. Pentru ca un cmp s nu fie salvat n procesul de serializare el trebuie declarat cu modificatorul transient i trebuie s fie nestatic. De exemplu, declararea unei variabile membre temporare ar trebui facut astfel: transient private double temp; // Ignorata la serializare Modificatorul static anuleaz efectul modificatorului transient. Cu alte cuvinte, variabilele de clas particip obligatoriu la serializare. static transient int N; // Participa la serializare n exemplele urmtoare cmpurile marcate DA particip la serializare, cele marcate NU, nu particip iar cele marcate cu Exceptie vor provoca excepii de tipul NotSerializableException. Dac un obiect ce trebuie serializat are referine la obiecte neserializabile, atunci va fi generat o excepie de tipul NotSerializableException. Atunci cnd o clas serializabila deriva dintr-o alt clas, salvarea cmpurilor clasei printe se va face doar dac i aceasta este serializabil. n caz contrar, subclasa trebuie s salveze explicit i cmpurile motenite. 3.1.3 Personalizarea serializrii obiectelor Dezavantajul mecanismului implicit de serializare este c algoritmul pe care se bazeaz, fiind creat pentru cazul general, se poate comporta ineficient n anumite situaii: poate fi mult mai lent dect este cazul sau reprezentarea binar generat pentru un obiect poate fi mult mai voluminoas dect ar trebui. n aceste situaii, putem s nlocuim algoritmul implicit cu unul propriu, particularizat pentru o clas anume. De asemenea, este posibil s extindem comportamentul implicit, adugnd i alte informaii necesare pentru serializarea unor obiecte.

Note

Programare orientat obiect n majoritatea cazurilor mecanismul standard este suficient, ns dup cum am spus, o clas poate avea nevoie de mai mult control asupra serializrii. Personalizarea serializarii se realizeaz prin definirea (ntr-o clas serializabil) a metodelor writeObject i readObject avnd exact signatura de mai jos: private void writeObject(java.io.ObjectOutputStream stream) throws IOException private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException Metoda writeObject controleaz ce date sunt salvate, iar readObject controleaz modul n care sunt restaurate obiectele, citind informaiile salvate i, eventual, modificnd starea obiectelor citite astfel nct ele s corespund anumitor cerine. n cazul n care nu dorim s nlocuim complet mecanismul standard, putem s folosim metodele defaultWriteObject, respectiv defaultReadObject care descriu procedurile implicite de serializare. Forma general de implementare a metodelor writeObject i readObject este: private void writeObject(ObjectOutputStream stream) throws IOException { // Procesarea campurilor clasei (criptare, etc.) ... // Scrierea obiectului curent stream.defaultWriteObject(); // Adaugarea altor informatii suplimentare ... } private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { // Restaurarea obiectului curent stream.defaultReadObject(); // Actualizarea starii obiectului (decriptare, etc.) si extragerea informatiilor suplimentare ... } Metodele writeObject i readObject sunt responsabile cu serializarea clasei n care sunt definite, serializarea superclasei sale fiind facut automat (i implicit). Dac ns o clas trebuie sa ii coordoneze serializarea proprie cu serializarea superclasei sale, atunci trebuie s implementeze interfaa Externalizable. a) Controlul versiunilor claselor Dac in urma serializarii, o clasa este modificat (se adauga noi atribute), la o rulare ulterioara se poate produce o excepie de tipul InvalidClassException. De ce se ntmpla acest lucru? Explicaia const n faptul c mecanismul de serializare Java este foarte atent cu signatura claselor serializate. Pentru fiecare obiect serializat este calculat automat un numr reprezentat pe 64 de bii, Note

91

92

Programare orientat obiect care reprezint un fel de amprent a clasei obiectului. Acest numr, denumit serialVersionUID, este generat pornind de la diverse informaii ale clasei, cum ar fi variabilele sale membre, (dar nu numai) i este salvat n procesul de serializare mpreun cu celelalte date. n plus, orice modificare semnificativ a clasei, cum ar fi adugarea unui nou cmp, va determina modificarea numrului su de versiune. La restaurarea unui obiect, numrul de versiune salvat n forma serializat va fi regsit i comparat cu noua semntur a clasei obiectului. n cazul n care acestea nu sunt egale, va fi generat o excepie de tipul InvalidClassException i deserializarea nu va fi fcut. Aceast abordare extrem de precaut este foarte util pentru prevenirea unor anomalii ce pot aprea cnd dou versiuni de clase sunt incompatibile, dar poate fi suprtoare atunci cnd modificrile aduse clasei nu stric compatibilitatea cu vechea versiune. n aceast situaie trebuie s comunicm explicit c cele dou clase sunt compatibile. Acest lucru se realizeaz prin setarea manual a variabilei serialVersionUID n cadrul clasei dorite, adugnd pur i simplu cmpul: static final long serialVersionUID = /* numar_serial_clasa */; Prezena variabilei serialVersionUID printre membrii unei clase va informa algoritmul de serializare c nu mai calculeze numrul de serie al clasei, ci s-l foloseasc pe cel specificat de noi. Cum putem afla numrul de serie al unei clase? Cu ajutorul utilitarului serialVer (permite generarea numrului serialVersionUID pentru o clas specificat): serialVer clasa b) Securizarea datelor Dup cum am vzut, membrii privai cum ar fi parola, particip la serializare. Problema const n faptul c, dei n format binar, informaiile unui obiect serializat nu sunt criptate n nici un fel i pot fi regsite cu uurin, ceea ce poate reprezenta un inconvenient atunci cnd exist cmpuri confideniale. Rezolvarea acestei probleme se face prin modificarea mecanismului implicit de serializare, implementnd metodele readObject i writeObject, precum i prin utilizarea unei funcii de criptare a datelor. c) Implementarea interfeei Externalizable Pentru un control complet, explicit, al procesului de serializare, o clas trebuie s implementeze interfaa Externalizable. Pentru instane ale acestor clase doar numele clasei este salvat automat pe fluxul de obiecte, clasa fiind responsabil cu scrierea i citirea membrilor si i trebuie s se coordoneze cu superclasele ei. Definiia interfeei Externalizable este: public interface Externalizable extends Serializable { public void writeExternal(ObjectOutput out) throws IOException; public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException; } Aadar, aceste clase trebuie s implementeze obligatoriu metodele writeExternal i readExternal n care se va face serializarea complet a obiectelor i coordonarea cu superclasa ei. Uzual, interfaa Externalizable este folosit n situaii n care se dorete

Note

Programare orientat obiect mbuntirea performanelor algoritmului standard, mai exact creterea vitezei procesului de serializare.

93

Test de autoevaluare: 1. Numiti fluxurile i metodele necesare serializarea/deserializarea unui obiect. pentru a realiza

2. Ce se salveaz la serializarea unui obiect?

3. Cum se exclud atribute de la serializare?

4. Ce tip implicit au obiectele deserializate?

5. Cum poate fi personalizat procesul de serializare?

Bibliografie : 1. Cristian Frsinaru Curs practic de Java 2. Bruce Eckel Thinking in Java 4th Edition, Ed. Prentice Hall, 2006, ISBN 0-13-187248-6 3. P. Niemeyer, J. Knudsen - Learning Java 3rd Edition, Ed. OReilly, 2005 4. .Tanas,.Andrei,C. Olaru Java de la 0 la expert, Ed.Polirom, 2007, ISBN 978-973-46-0317-6 Note

94

Programare orientat obiect 5. D.Danciu, G.Mardale - Arta programrii n JAVA (Vol. I) Elemente-suport fundamentale, Ed. Albastr, 2005

Note

Programare orientat obiect 3.2 3 Fire de execuie

95

Obiective: Cunoaterea no terea noiunii de programare concurent prin folosirea firelor de execu execuie Cunoaterea modalit terea modalitilor de lucru cu firele de execuie Cunoaterea ciclului de via a unui fir de execuie terea via Cunoaterea modului de setare a priorit terea prioritilor i de sincronizare i a firelor de execu execuie 3.2.1 Introducere Firele de execuie fac trecerea de la programarea secven ie ie secvenial secvenial la programarea concurent. Un program secven . secvenial reprezint modelul clasic de program: are un nceput, o secven de execuie a instruciunilor sale i un sfr : secven i sfrit. Cu alte cuvinte, la un moment dat programul are un singur punct de execu execuie. execu Un program aflat n execuie se nume proces. Un sistem de operare monotasking, ie numete . cum ar fi MS-DOS, nu este capabil s execute dect un singur proces la un s moment dat, n timp ce un sistem de operare multitasking, cum ar fi UNIX sau Windows, poate rula oricte procese n acela i timp (concurent), folosind diverse acelai strategii de alocare a procesorului fiec fiecruia dintre acestea. Am reamintit acest lucru deoarece no noiunea de fir de execuie nu are sens ie dect n cadrul unui sistem de operare multitasking. Un fir de execuie este similar unui proces secven ial, n sensul c are un ie secvenial, nceput, o secven de execuie i un sfrit. Diferena dintre un fir de execu i a execuie un proces const n faptul c un fir de execuie nu poate rula independent ci ie trebuie s ruleze n cadrul unui proces. Definiie: Un fir de execu este o succesiune secvenial de instruc execuie instruciuni care se execut n cadrul unui proces. Un program i poate defini nu doar un fir de execu ie ci oricte, ceea ce i execuie nseamn c n cadrul unui proces se pot executa simultan mai multe fire de execuie, permind efectuarea concurent a sarcinilor independente ale acelui nd concurent program. Un fir de execuie poate fi asem ie asemnat cu o versiune redus a unui proces, ambele rulnd simultan i independent pe o structur secvenial format de structur format instruciunile lor. De asemenea, execu simultan a firelor n cadrul unui proces iunile execuia este similar cu execuia concurent a proceselor: sistemul de operare va aloca ia concurent procesorul dup o anumit strategie fiec fiecrui fir de execuie pn la terminarea lor. Din acest motiv firele de execu mai sunt numite i procese uoare. execuie Care ar fi ns deosebirile ntre un fir de execuie i un proces? n primul, i rnd deosebirea major const n faptul c firele de execuie nu pot rula dect n ie cadrul unui proces. O alt deosebire rezult din faptul c fiecare proces are rezult propria sa memorie (propriul s spaiu de adrese) iar la crearea unui nou proces su drese) (fork) este realizat o copie exact a procesului printe: cod i date, n timp ce la exact i crearea unui fir nu este copiat dect codul procesului p rinte, toate firele de printe, execuie avnd acces la acelea date, datele procesului original. ie aceleai Aadar, un fir mai poate fi privit i ca un context de execuie n cadrul adar, ie unui proces. Note

96

Programare orientat obiect Firele de execuie sunt utile n multe privine, ns uzual ele sunt folosite pentru executarea unor operaii consumatoare de timp fr a bloca procesul principal: calcule matematice, ateptarea eliberrii unei resurse, desenarea componentelor unei aplicaii GUI, etc. De multe ori ori, firele i desfoar activitatea n fundal ns, evident, acest lucru nu este obligatoriu. 3.2.2 Crearea unui fir de execuie Ca orice alt obiect Java, un fir de execuie este o instan a unei clase. Firele de execuie definite de o clas vor avea acelai cod i, prin urmare, aceeai secvena de instruciuni. Crearea unei clase care s defineasc fire de execuie poate fi facut prin dou modaliti: prin extinderea clasei Thread prin implementarea interfeei Runnable Orice clas ale crei instane vor fi executate separat ntr-un fir propriu trebuie declarat ca fiind de tip Runnable. Aceasta este o interfa care conine o singur metod i anume metoda run. Aadar, orice clas ce descrie fire de execuie va conine metoda run n care este implementat codul ce va fi rulat. Interfaa Runnable este conceput ca fiind un protocol comun pentru obiectele care doresc s execute un anumit cod pe durata existenei lor. Cea mai important clas care implementeaz interfaa Runnable este Thread. Aceasta implementeaz un fir de execuie generic care, implicit, nu face nimic; cu alte cuvinte, metoda run nu conine nici un cod. Orice fir de execuie este o instan a clasei Thread sau a unei subclase a sa. a) Extinderea clasei Thread Cea mai simpl metod de a crea un fir de execuie care s realizeze o anumit aciune este prin extinderea clasei Thread i supradefinirea metodei run a acesteia. Formatul general al unei astfel de clase este: public class FirExcecutie extends Thread { public FirExcecutie(String nume) { // Apelam constructorul superclasei super(nume); } public void run() { // Codul firului de executie ... } } Prima metod a clasei este constructorul, care primete ca argument un ir ce va reprezenta numele firului de execuie. n cazul n care nu vrem s dm nume firelor pe care le crem, atunci putem renuna la supradefinirea acestui constructor i s folosim constructorul implicit, fr argumente, care creeaz un fir de execuie fr nici un nume. Ulterior, acesta poate primi un nume cu metoda setName. Evident, se pot defini i ali constructori, acetia fiind utili atunci cnd vrem s trimitem diveri parametri de iniializare firului nostru. A dou metod este metoda run, inima oricrui fir de execuie, n care scriem efectiv codul care trebuie s se execute. Un fir de execuie creat nu este automat pornit, lansarea s fiind realizeaz de metoda start, definit n clasa Thread. // Cream firul de executie FirExecutie fir = new FirExecutie("simplu");

Note

Programare orientat obiect // Lansam in executie fir.start(); S considerm n continuare un exemplu n care definim un fir de execuie ce afieaz numerele ntregi dintr-un interval, cu un anumit pas. Exemplu de folosire a clasei Thread: class AfisareNumere extends Thread { private int a, b, pas; public AfisareNumere (int a, int b, int pas ) { this.a = a; this.b = b; this.pas = pas; } public void run () { for (int i = a; i <= b; i += pas) System.out.print (i + " " ); } } public class TestThread { public static void main (String args []) { AfisareNumere fir1 , fir2 ; fir1 = new AfisareNumere (0, 100 , 5); // Numara de la 0 la 100 cu pasul 5 fir2 = new AfisareNumere (100 , 200 , 10); // Numara de la 100 la 200 cu pasul 10 fir1.start (); fir2.start (); // Pornim firele de executie // Ele vor fi distruse automat la terminarea lor } } Gndind secvenial, s-ar crede c acest program va afia prima dat numerele de la 0 la 100 cu pasul 5, apoi numerele de la 100 la 200 cu pasul 10, ntruct primul apel este ctre contorul fir1, deci rezultatul afiat pe ecran ar trbui s fie: 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 100 110 120 130 140 150 160 170 180 190 200 n realitate ns, rezultatul obinut va fi o intercalare de valori produse de cele dou fire ce ruleaz simultan. La rulri diferite se pot obine rezultate diferite deoarece timpul alocat fiecrui fir de execuie poate s nu fie acelai, el fiind controlat de procesor ntr-o manier aparent aleatoare. Un posibil rezultat al programului de mai sus: 0 100 5 110 10 120 15 130 20 140 25 150 160 170 180 190 200 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 Trebuie menionat c rezultatele obinute depind direct de maina pe care lucreaz, mai exact de procesor, astfel c este posibil de exemplu ca pentru unele sarcini simple, ele s aib suficient timp s se execute n ntregime ntr-o singur bucat de timp alocat de ctre procesor, fr a mai ajunge ca rulrile lor s fie intercalate.

97

Note

98

Programare orientat obiect b) Implementarea interfeei Runnable Ce facem ns cnd dorim s crem o clas care instaniaz fire de execuie dar aceasta are deja o superclas, tiind c n Java nu este permis motenirea multipl ? class FirExecutie extends Parinte, Thread // Incorect ! n acest caz, nu mai putem extinde clasa Thread ci trebuie s implementm direct interfaa Runnable. Clasa Thread implementeaz ea nsi interfaa Runnable i, din acest motiv, la extinderea ei obineam implementarea indirect a interfeei. Aadar, interfa Runnable permite unei clase s fie activ, fr a extinde clasa Thread. Interfaa Runnable se gsete n pachetul java.lang i este definit astfel: public interface Runnable { public abstract void run(); } Prin urmare, o clas care instaniaz fire de execuie prin implementarea interfeei Runnable trebuie obligatoriu s implementeze metoda run. O astfel de clas se mai numete clas activ i are urmtoarea structur: public class ClasaActiva implements Runnable { public void run() { //Codul firului de executie ... } } Spre deosebire de modalitatea anterioar, se pierde ns tot suportul oferit de clasa Thread. Simpla instaniere a unei clase care implemeneaz interfaa Runnable nu creeaz nici un fir de execuie, crearea acestora trebuind fcut explicit. Pentru a realiza acest lucru trebuie s instaniem un obiect de tip Thread ce va reprezenta firul de execuie propriu zis al crui cod se gasete n clasa noastr. Acest lucru se realizeaz, ca pentru orice alt obiect, prin instruciunea new, urmat de un apel la un constructor al clasei Thread, ns nu la oricare dintre acetia. Trebuie apelat constructorul care s primeasc drept argument o instan a clasei noastre. Dup creare, firul de execuie poate fi lansat printr-un apel al metodei start. ClasaActiva obiectActiv = new ClasaActiva(); Thread fir = new Thread(obiectActiv); fir.start(); Aceste operaiuni pot fi fcute chiar n cadrul clasei noastre: public class FirExecutie implements Runnable { private Thread fir = null; public FirExecutie() if (fir == null) fir = new Thread(this); } public void run() { //Codul firului de executie ... } } Specificarea argumentului this n constructorul clasei Thread determin crearea unui fir de execuie care, la lansarea sa, va apela metoda run din clasa curent. Aadar, acest constructor accept ca argument orice instan a unei

Note

Programare orientat obiect clase Runnable. Pentru clasa FirExecutie dat mai sus, lansarea firului va fi fcut automat la instanierea unui obiect al clasei: FirExecutie fir = new FirExecutie(); Atenie! Metoda run nu trebuie apelat explicit, acest lucru realizndu-se automat la apelul metodei start. Apelul explicit al metodei run nu va furniza nici o eroare, ns aceasta va fi executat ca orice alt metoda, i nu separat ntr-un fir. 3.2.3 Ciclul de via al unui fir de execuie Fiecare fir de execuie are propriul su ciclu de via: este creat, devine activ prin lansarea sa i, la un moment dat, se termin. n continuare, vom analiza mai ndeaproape strile n care se poate gsi un fir de execuie. Un fir de execuie se poate gsi n una din urmtoarele patru stri: New Thread Runnable Not Runnable Dead Starea New Thread Un fir de execuie se gsete n aceast stare imediat dup crearea sa, cu alte cuvinte dup instanierea unui obiect din clasa Thread sau dintr-o subclas a sa. Thread fir = new Thread(obiectActiv); // fir se gaseste in starea "New Thread" n aceast stare firul este vid, el nu are alocate nici un fel de resurse sistem i singura operaiune pe care o putem executa asupra lui este lansarea n execuie, prin metoda start. Apelul oricrei alte metode n afar de start nu are nici un sens i va provoca o excepie de tipul IllegalThreadStateException. Starea Runnable Dup apelul metodei start un fir va trece n starea Runnable, adic va fi n execuie. fir.start(); //fir se gaseste in starea "Runnable" Metoda start realizez urmtoarele operaiuni necesare rulrii firului de execuie: Aloc resursele sistem necesare. Planific firul de execuie la procesor pentru a fi lansat. Apeleaz metoda run a obiectului activ al firului. Un fir aflat n starea Runnable nu nseamn neaprat c se geste efectiv n execuie, adic instruciunile sale sunt interpretate de procesor. Acest lucru se ntmpl din cauza c majoritatea calculatoarelor au un singur procesor, iar acesta nu poate rula simultan toate firele de execuie care se gasesc n starea Runnable. Pentru a rezolva aceasta problem exist o planificare care s partajeze dinamic i corect procesorul ntre toate firele de execuie care sunt n starea Runnable. Aadar, un fir care ruleaz poate s-i atepte de fapt rndul la procesor. Starea Not Runnable Un fir de execuie poate ajunge n aceaat stare n una din urmtoarele situaii: Este adormit prin apelul metodei sleep; A apelat metoda wait, ateptnd ca o anumit condiie s fie satisfacut;

99

Note

100

Programare orientat obiect Este blocat ntr-o operaie de intrare/ieire. Metoda sleep este o metod static a clasei Thread care provoac o pauz n timpul rulrii firului curent aflat n execuie, cu alte cuvinte l adoarme pentru un timp specificat. Lungimea acestei pauze este specificat n milisecunde i chiar nanosecunde. Intruct poate provoca excepii de tipul InterruptedException, apelul acestei metode se face ntr-un bloc de tip try-cacth: try { // Facem pauza de o secunda Thread.sleep(1000); } catch (InterruptedException e) { ... } Observai c metoda fiind static apelul ei nu se face pentru o instan anume a clasei Thread. Acest lucru este foarte normal deoarece, la un moment dat, un singur fir este n execuie i doar pentru acesta are sens adormirea sa. n intervalul n care un fir de execuie doarme, acesta nu va fi executat chiar dac procesorul devine disponibil. Dup expirarea intervalului specificat firul revine n starea Runnable iar dac procesorul este n continuare disponibil si va continua execuia. Pentru fiecare tip de intrare n starea Not Runnable, exist o secven specific de ieire din starea repectiv, care readuce firul de execuie n starea Runnable. Acestea sunt: Dac un fir de execuie a fost adormit, atunci el devine Runnable doar dup scurgerea intervalului de timp specificat de instruciunea sleep. Dac un fir de execuie ateapt o anumit condiie, atunci un alt obiect trebuie s l informeze dac acea condiie este ndeplinit sau nu; acest lucru se realizeaz prin instruciunile notify sau notifyAll. Dac un fir de execuie este blocat ntr-o operaiune de intrare/ieire atunci el redevine Runnable atunci cnd acea operaiune s-a terminat. Starea Dead Este starea n care ajunge un fir de execuie la terminarea sa. Un fir nu poate fi oprit din program printr-o anumit metod, ci trebuie s se termine n mod natural la ncheierea metodei run pe care o execut. Spre deosebire de versiunile curente ale limbajului Java, n versiunile mai vechi exista metoda stop a clasei Thread care termina forat un fir de execuie, ns aceasta a fost eliminat din motive de securitate. Aadar, un fir de execuie trebuie s-i aranjeze singur propria sa moarte. a) Terminarea unui fir de execuie Dup cum am vazut, un fir de execuie nu poate fi terminat forat de ctre program ci trebuie s-i aranjeze singur terminarea sa. Acest lucru poate fi realizat n dou modaliti: 1) Prin scrierea unor metode run care s-i termine execuia n mod natural. La terminarea metodei run se va termina automat i firul de execuie, acesta intrnd n starea Dead. Ambele exemple anteriorare se ncadreaz n aceast categorie. Exemplu : public void run() { for(int i = a; i <= b; i += pas) System.out.print(i + " " ); }

Note

Programare orientat obiect Dup afiarea numerelor din intervalul specificat, metoda se termin i, odat cu ea, se va termina i firul de execuie repsectiv. 2) Prin folosirea unei variabile de terminare. n cazul cnd metoda run trebuie s execute o bucl infinit atunci aceasta trebuie controlat printr-o variabil care s opreasc ciclul atunci cnd dorim ca firul de execuie s se termine. Uzual, vom folosi o variabil membr a clasei care descrie firul de execuie care fie este public, fie este asociat cu o metod public care permite schimbarea valorii sale. Nu este necesar distrugerea explicit a unui fir de execuie. Sistemul Java de colectare a gunoiului se ocup de acest lucru. Setarea valorii null pentru variabila care referea instana firului de execuie va uura ns activitatea procesului gc. Metoda System.exit va oprit forat toate firele de execuie i va termina aplicaia curent. Pentru a testa dac un fir de execuie a fost pornit dar nu s-a terminat nc putem folosi metoda isAlive. Metoda returneaz: true - dac firul este n una din strile Runnable sau Not Runnable false - dac firul este n una din starile New Thread sau Dead b) Fire de execuie de tip daemon Un proces este considerat n execuie dac conine cel puin un fir de execuie activ. Cu alte cuvinte, la rularea unei aplicaii, maina virtual Java nu se va opri dect atunci cnd nu mai exist nici un fir de execuie activ. De multe ori ns dorim s folosim fire care s realizeze diverse activiti, eventual periodic, pe toat durata de execuie a programului, iar n momentul terminrii acestuia s se termine automat i firele respective. Aceste fire de execuie se numesc demoni. Dup crearea sa, un fir de execuie poate fi fcut demon, sau scos din aceast stare, cu metoda setDaemon. c) Stabilirea prioritilor de execuie Majoritatea calculatoarelor au un sigur procesor, ceea ce nseamn c firele de execuie trebuie s ii mpart accesul la acel procesor. Execuia ntr-o anumit ordine a mai multor fire de execuie pe un numr limitat de procesoare se numete planificare (scheduling). Sistemul Java de execuie a programelor implementeaz un algoritm simplu, determinist de planificare, cunoscut sub numele de planificare cu prioriti fixate. Fiecare fir de execuie Java primete la crearea sa o anumit prioritate. O prioritate este de fapt un numr ntreg cu valori cuprinse ntre MIN PRIORITY i MAX PRIORITY. Implicit, prioritatea unui fir nou creat are valoarea NORM PRIORITY. Aceste trei constante sunt definite n clasa Thread astfel: public static final int MAX_PRIORITY = 10; public static final int MIN_PRIORITY = 1; public static final int NORM_PRIORITY= 5; Schimbarea ulterioar a prioritii unui fir de execuie se realizeaz cu metoda setPriority a clasei Thread. La nivelul sistemului de operare, exist dou modele de lucru cu fire de execuie: Note

101

102

Programare orientat obiect Modelul cooperativ, n care firele de execuie decid cnd s cedeze procesorul; dezavantajul acestui model este c unele fire pot acapara procesorul, nepermind i execuia altora pn la terminarea lor. Modelul preemptiv, n care firele de execuie pot fi ntrerupte oricnd, dup ce au fost lsate s ruleze o perioad, urmnd s fie reluate dup ce i celelalte fire aflate n execuie au avut acces la procesor; acest sistem se mai numete cu cuante de timp, dezavantajul su fiind nevoia de a sincroniza accesul firelor la resursele comune. Aadar, m modelul cooperativ firele de execuie sunt responsabile cu partajarea timpului de execuie, n timp ce n modelul preemptiv ele trebuie s partajeze resursele comune. Deoarece specificaiile mainii virtuale Java nu impun folosirea unui anumit model, programele Java trebuie scrise astfel nct s funcioneze corect pe ambele modele. d) Sincronizarea firelor de execuie Pn acum am vzut cum putem crea fire de execuie independente i asincrone, cu alte cuvinte care nu depind n nici un fel de execuia sau de rezultatele altor fire. Exist ns numeroase situaii cnd fire de execuie separate, dar care ruleaz concurent, trebuie s comunice ntre ele pentru a accesa diferite resurse comune sau pentru a-i transmite dinamic rezultatele muncii lor. Cel mai elocvent scenariu n care firele de execuie trebuie s se comunice ntre ele este cunoscut sub numele de problema productorului/consumatorului, n care productorul genereaz un flux de date care este preluat i prelucrat de ctre consumator. S considerm de exemplu o aplicaie Java n care un fir de execuie (productorul) scrie date ntr-un fiier n timp ce alt fir de execuie (consumatorul) citete date din acelai fiier pentru a le prelucra. Sau, s presupunem c productorul genereaz nite numere i le plaseaz, pe rnd, ntrun buffer iar consumatorul citete numerele din acel buffer pentru a le procesa. n ambele cazuri avem de-a face cu fire de execuie concurente care folosesc o resurs comun: un fiier, respectiv o zon de memorie i, din acest motiv, ele trebuie sincronizate ntr-o manier care s permit decurgerea normal a activitii lor. Exist diverse mecanisme prin care se poate obine sincronizarea. 3.2.4 Comunicarea prin fluxuri de tip pipe O modalitate deosebit de util prin care dou fire de execuie pot comunica este realizat prin intermediul canalelor de comunicatii (pipes). Acestea sunt implementate prin fluxuri descrise de clasele: PipedReader, PipedWriter - pentru caractere, respectiv PipedOutputStream, PipedInputStream - pentru octei. Fluxurile pipe de ieire i cele de intrare pot fi conectate pentru a efectua transmiterea datelor. Acest lucru se realizeaz uzual prin intemediul constructorilor: public PipedReader(PipedWriterpw) public PipedWriter(PipedReaderpr) n cazul n care este folosit un constructor fr argumente, conectarea unui flux de intrare cu un flux de ieire se face prin metoda connect: public void connect(PipedWriterpw) public void connect(PipedReaderpr) Intru-ct fluxurile care sunt conectate printr-un pipe trebuie s execute simultan operaii de scriere/citire, folosirea lor se va face din cadrul unor fire de

Note

Programare orientat obiect execuie. Funcionarea obicetelor care instaniaz PipedWriter i PipedReader este asemntoare cu a canalelor de comunicare UNIX (pipes). Fiecare capt al unui canal este utilizat dintr-un fir de execuie separat. La un capt se scriu caractere, la cellalt se citesc. La citire, dac nu sunt date disponibile firul de execuie se va bloca pn ce acestea vor deveni disponibile. Se observ c acesta este un comportament tipic productor-consumator asincron, firele de execuie comunicnd printr-un canal. Realizarea conexiunii se face astfel: PipedWriter pw1 = new PipedWriter(); PipedReader pr1 = new PipedReader(pw1); // sau PipedReader pr2 = new PipedReader(); PipedWriter pw2 = new PipedWriter(pr2); // sau PipedReader pr = new PipedReader(); PipedWriter pw = new PipedWirter(); pr.connect(pw) //echivalent cu pw.connect(pr); Scrierea i citirea pe/de pe canale se realizeaz prin metodele uzuale read i write, n toate formele lor.

103

Test de autoevaluare: 1. Care este utilitatea firelor de execuie?

2. Care sunt modalitile de creare a unei clase pentru lucrul cu fire de execuie?

3. Care sunt strile posibile ale unui fir de execuie?

Note

104

Programare orientat obiect 4. Cum pot fi modificate prioritile ataate firelor de execuie?

5. Care este utilitatea sincronizrii firelor de execuie ?

Bibliografie : 1. Cristian Frsinaru Curs practic de Java 2. Bruce Eckel Thinking in Java 4th Edition, Ed. Prentice Hall, 2006, ISBN 0-13-187248-6 3. P. Niemeyer, J. Knudsen - Learning Java 3rd Edition, Ed. OReilly, 2005 4. .Tanas,.Andrei,C. Olaru Java de la 0 la expert, Ed.Polirom, 2007, ISBN 978-973-46-0317-6 5. D.Danciu, G.Mardale - Arta programrii n JAVA (Vol. I) Elemente-suport fundamentale, Ed. Albastr, 2005 Note

Programare orientat obiect 3.3 Organizarea claselor

105

Obiective: nelegerea utilit elegerea utilitii gruprii claselor n pachete Cunoaterea modului de plasare a claselor n pachete terea Crearea i lucrul cu arhive .jar Crearea documenta documentaiei folosind utilitarul javadoc

3.3.1 Pachete colecie e Definiie: Un pachet este o colec de clase i interfee nrudite din punctul de vedere al funcionalitii lor. Sunt folosite pentru gsirea i utilizarea mai u ii i uoar a claselor, pentru a evita conflictele de nume i pentru a controla accesul la i anumite clase. n alte limbaje de programare pachetele se mai numesc libr librrii libr sau bibilioteci. a) Pachetele standard (J2SD (J2SDK) Platforma standard de lucru Java se bazeaz pe o serie de pachete cu bazeaz ajutorul crora se pot construi ntr manier simplificat aplicaiile. Exist deci rora ntr-o iile. un set de clase deja implementate care modeleaz structuri de date, algoritmi sau modeleaz diverse noiuni eseniale n dezvoltarea unui program. Cele mai importante iale pachete i suportul oferit de lor sunt: i java.lang - clasele de baz ale limbajului Java java.io - intrri/ieiri, lucrul cu fi iri, fiiere java.util - clase i interfee utile e java.applet - dezvoltarea de appleturi area java.awt - interfaa grafic cu utilizatorul java.awt.event - mecanismele de tratare e evenimentelor generate de utilizator java.beans - scrierea de componente reutilizabile java.net - programare de reea ea java.sql - lucrul cu baze de date java.rmi - execuie la distan Remote Message Interface ie java.security - mecanisme de securitate: criptare, autentificare java.math - operaii matematice cu numere mari ii java.text - lucrul cu texte, date i numere independent de limb java.lang.reflect - introspecie javax.swing - interfaa grafic cu utilizatorul, mult mbogit fa de AWT. a b) Folosirea membrilor unui pachet Conform specificaiilor de acces ale unei clase i ale mebrilor ei, doar iilor i clasele publice i membrii declara i publici ai unei clase sunt accesibili n afara i declarai pachetului n care se gsesc. Dup cum am vzut deja, accesul implicit n Java sesc. zut este la nivel de pachet. Pentru a folosi o clas public dintr-un anumit pachet, sau pentru a apela public un o metod public a unei clase publice a unui pachet, exist trei soluii: exist specificarea numelui complet al clasei importul clasei respective importul ntregului pachet n care se gsete clasa.

Note

106

Programare orientat obiect Specificarea numelui complet al clasei se face prin prefixarea numelui scurt al clasei cu numele pachetului din care face parte: numePachet.NumeClasa Button - numele scurt al clasei java.awt - pachetul din care face parte java.awt.Button - numele complet al clasei Aceast metod este recomandat doar pentru cazul n care folosirea acelei clase se face o singur dat sau foarte rar. De exemplu, ar fi extrem de neplcut s scriem de fiecare dat cnd vrem s declarm un obiect grafic secvene de genul: java.awt.Button b1 = new java.awt.Button("OK"); 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"); n aceste situaii, vom importa n aplicaia noastr clasa respectiv, sau ntreg pachetul din care face parte. Acest lucru se realizeaz prin instruciunea import, care trebuie s apar la nceputul fiierelor surs, nainte de declararea vreunei clase sau interfee. c) Importul unei clase sau interfee Se face prin instruciunea import n care specificm numele complet al clasei sau interfeei pe care dorim s o folosim dintr-un anumit pachet: import numePachet.numeClasa; //Pentru exemplul nostru: import java.awt.Button; import java.awt.TextField; Din acest moment, vom putea folosi n clasele fiierului n care am plasat instruciunea de import numele scurt al claselor Button i TextField: Button b1 = new Button("OK"); Button b2 = new Button("Cancel"); TextField tf1 = new TextField("Placut"); TextField tf2 = new TextField("Foarte placut"); Aceast abordare este eficient i recomandat n cazul n care nu avem nevoie dect de cteva clase din pachetul respectiv. d) Importul la cerere dintr-un pachet Dac avem nevoie de mai multe clase dintr-un anumit pachet, ar trebui s avem cte o instruciune de import pentru fiecare dintre ele. n aceast situaie ar fi mai simplu s folosim importul la cerere din ntregul pachet i nu al fiecrei clase n parte. Importul la cerere dintr-un anumit pachet se face printr-o instruciune import n care specificm numele pachetului ale crui clase i interfee dorim s le folosim, urmat de simbolul *. Se numete import la cerere deoarece ncrcarea claselor se face dinamic, n momentul apelrii lor. import numePachet.*; //Pentru exemplul nostru: import java.awt.*; Din acest moment, vom putea folosi n clasele fiierului n care am plasat instruciunea de import numele scurt al tuturor claselor pachetului importat. Note Atenie! Caracterul * nu are semnificaia uzual de la fiiere de wildcard (masc) i nu poate fi folosit dect ca atare. O expresie de genul import

Programare orientat obiect java.awt.C*; va produce o eroare de compilare. n cazul n care sunt importate dou sau mai multe pachete care conin clase (interfee) cu acelai nume, atunci referirea la ele trebuie fcut doar folosind numele complet, n caz contrar fiind semnalat o ambiguitate de ctre compilator. import java.awt.*; // Contine clasa List import java.util.*; // Contine interfata List ... List x; //Declaratie ambigua java.awt.List a = new java.awt.List(); //corect java.util.List b = new ArrayList(); //corect Sunt considerate importate automat, pentru orice fiier surs, urmtoarele pachete: pachetul java.lang : import java.lang.*; pachetul curent pachetul implicit (fr nume) e) Importul static Aceast facilitate, introdus ncepnd cu versiunea 1.5, permite referirea constantelor statice ale unei clase fr a mai specifica numele complet al acesteia i este implementat prin adugarea cuvntului cheie static dup cel de import: import static numePachet.NumeClasa.*; Astfel, n loc s ne referim la constantele clasei cu expresii de tipul NumeClasa.CONSTANTA, putem folosi doar numele constantei. // Inainte de versiuna 1.5 import java.awt.BorderLayout.*; ... fereastra.add(new Button(), BorderLayout.CENTER); // Incepand cu versiunea 1.5 import java.awt.BorderLayout.*; import static java.awt.BorderLayout.*; ... fereastra.add(new Button(), CENTER); Atenie! Importul static nu import dect constantele statice ale unei clase, nu i clasa n sine. f) Crearea unui pachet Toate clasele i interfeele Java apartin la diverse pachete, grupate dup funcionalitatea lor. Dup cum am vzut clasele de baz se gsesc n pachetul java.lang, clasele pentru intrri/ieiri sunt n java.io, clasele pentru interfaa grafic n java.awt, etc. Crearea unui pachet se realizeaz prin scriere la nceputul fiierelor surs ce conin clasele i interfeele pe care dorim s le grupm ntr-un pachet a instruciunii: package numePachet; S considerm un exemplu: presupunem c avem dou fiiere surs Graf.java i Arbore.java. //Fisierul Graf.java Note

107

108 package grafuri; class Graf {...} class GrafPerfect extends Graf {...}

Programare orientat obiect

//Fisierul Arbore.java package grafuri; class Arbore {...} class ArboreBinar extends Arbore {...} Clasele Graf, GrafPerfect, Arbore, ArboreBinar vor face parte din acelai pachet grafuri. Instruciunea package acioneaz asupra ntregului fiier surs la nceputul cruia apare. Cu alte cuvinte nu putem specifica faptul c anumite clase dintr-un fiier surs aparin unui pachet, iar altele altui pachet. Dac nu este specificat un anumit pachet, clasele unui fiier surs vor face parte din pachetul implicit (care nu are nici un nume). n general, pachetul implicit este format din toate clasele i intefeele directorului curent de lucru. Este recomandat ns ca toate clasele i intefetele s fie plasate n pachete, pachetul implicit fiind folosit doar pentru aplicaii mici sau prototipuri. 3.3.2 Organizarea fiierelor a) Organizarea fiierelor surs Orice aplicaie nebanal trebuie s fie construit folosind o organizare ierarhic a componentelor sale. Este recomandat ca strategia de organizare a fiierelor surs s respecte urmtoarele convenii: Codul surs al claselor i interfeelor s se gaseasc n fiiere ale cror nume s fie chiar numele lor scurt i care s aib extensia .java. Atenie! Este obligatoriu ca o clas/interfa public s se gaseasc ntr-un fiier avnd numele clasei(interfeei) i extenisa .java, sau compilatorul va furniza o eroare. Din acest motiv, ntr-un fiier surs nu pot exista dou clase sau interfee publice. Pentru clasele care nu sunt publice acest lucru nu este obligatoriu, ci doar recomandat. ntr-un fiier surs pot exista oricte clase sau interfee care nu sunt publice. Fiierele surs trebuie s se gseasc n directoare care s reflecte numele pachetelor n care se gsesc clasele i interfeele din acele fiiere. Cu alte cuvinte, un director va conine surse pentru clase i interfee din acelai pachet iar numele directorului va fi chiar numele pachetului. Dac numele pachetelor sunt formate din mai multe uniti lexicale separate prin punct, atunci acestea trebuie deasemenea s corespund unor directoare ce vor descrie calea spre fiierele surs ale cror clase i interfee fac parte din pachetele respective. Vom clarifica modalitatea de organizare a fiierelor surs ale unei aplicatii printr-un exemplu concret. S presupunem c dorim crearea unor componente care s reprezinte diverse noiuni matematice din domenii diferite, cum ar fi geometrie, algebr, analiz, etc. Pentru a simplifica lucrurile, s presupunem c dorim s crem clase care s descrie urmtoarele notiuni: poligon, cerc, poliedru, sfer, grup, funcie. O prim variant ar fi s construim cte o clas pentru fiecare i s le plasm n acelai director mpreuna cu un program care s le foloseasca, ns, avnd n vedere posibila extindere a aplicaiei cu noi reprezentri de noiuni matematice, aceast abordare ar fi ineficient. O abordare elegant ar fi aceea n care clasele care descriu noiuni din

Note

Programare orientat obiect acelai domeniu sa se gaseasca n pachete separate i directoare separate. Ierarhia fiierelor sursa ar fi: /matematica /surse /geometrie /plan Poligon.java Cerc.java /spatiu Poliedru.java Sfera.java /algebra Grup.java /analiza Functie.java Matematica.java Clasele descrise n fiierele de mai sus trebuie declarate n pachete denumite corespunzator cu numele directoarelor n care se gasesc: // Poligon.java package geometrie.plan; public class Poligon { . . . } // Cerc.java package geometrie.plan; public class Cerc { . . . } // Poliedru.java package geometrie.spatiu; public class Poliedru { . . . } // 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 aplicaiei. Dup cum se observ, numele lung al unei clase trebuie s descrie calea spre acea clas n cadrul fiierelor surs, relativ la directorul n care se gsete aplicaia. b) Organizarea unitilor de compilare (.class) n urma compilrii fiierelor surs vor fi generate uniti de compilare pentru fiecare clas i interfa din fiierele surs. Dup cum tim acestea au extensia .class i numele scurt al clasei sau interfeei respective. Note

109

110

Programare orientat obiect Spre deosebire de organizarea surselor, un fiier .class trebuie s se gaseasca ntr-o ierarhie de directoare care s reflecte numele pachetului din care face parte clasa respectiv. Implicit, n urma compilrii fiierele surs i unitile de compilare se gsesc n acelai director, ns ele pot fi apoi organizate separat. Este recomandat ns ca aceast separare s fie fcut automat la compilare. Revenind la exemplul de mai sus, vom avea urmtoarea organizare: /matematica /clase /geometrie /plan Poligon.class Cerc.class /spatiu Poliedru.class Sfera.class /algebra Grup.class /analiza Functie.class Matematica.class Crearea acestei structuri ierarhice este facut automat de ctre compilator. n directorul aplicatiei (matematica) crem subdirectorul clase i dm comanda: javac -sourcepath surse surse/Matematica.java -d clase sau javac -classpath surse surse/Matematica.java -d clase Opiunea -d specific directorul rdcin al ierarhiei de clase. n lipsa lui, fiecare unitate de compilare va fi plasat n acelai director cu fiierul su surs. Deoarece compilm clasa principal a aplicaiei, vor fi compilate n cascad toate clasele referite de aceasta, dar numai acestea. n cazul n care dorim s compilm explicit toate fiierele java dintr-un anumit director, de exemplu surse/geometrie/plan, putem folosi expresia: javac surse/geometrie/plan/*.java -d clase c) Necesitatea organizrii fiierelor Organizarea fiierelor surs este necesar deoarece n momentul cnd compilatorul ntlneste un nume de clas el trebuie s poat identifica acea clas, ceea ce nseamna c trebuie s gaseasc fierul surs care o conine. Similar, unitile de compilare sunt organizate astfel pentru a da posibilitatea interpretorului s gaseasc i s ncarce n memorie o anumit clas n timpul execuiei programului. Ins aceast organizare nu este suficient deoarece specific numai partea final din calea ctre fiierele .java i .class, de exemplu /matematica/clase/geometrie/plan/Poligon.class. Pentru aceasta, att la compilare ct i la interpretare trebuie specificat lista de directoare rdcin n care se gsesc fiierele aplicaiei. Aceast list se numete cale de cautare (classpath). Definiie: O cale de cutare este o list de directoare sau arhive n care vor fi cutate fiierele necesare unei aplicaii. Fiecare director din calea de cautare este directorul imediat superior structurii de directoare corespunztoare numelor

Note

Programare orientat obiect pachetelor n care se gsesc clasele din directorul respectiv, astfel nct compilatorul i interpretorul s poat construi calea complet spre clasele aplicaiei. Implicit, calea de cutare este format doar din directorul curent. Identificarea unei clase referite n program se face n felul urmtor: La directoarele aflate n calea de cutare se adaug subdirectoarele specificate n import sau n numele lung al clasei n directoarele formate este cutat un fiier cu numele clasei. n cazul n care nu este gsit nici unul sau sunt gsite mai multe va fi semnalat o eroare. d) Setarea cii de cutare (CLASSPATH) Setarea cii de cutare se poate face n dou modaliti: Setarea variabilei de mediu CLASSPATH - folosind aceast variant toate aplicaiile Java de pe maina respectiv vor cuta clasele necesare n directoarele specificate n variabila CLASSPATH. UNIX: SET CLASSPATH = cale1:cale2:... DOS shell (Windows 95/NT/...): SET CLASSPATH = cale1;cale2;... Folosirea opiunii -classpath la compilarea i interpretarea programelor directoarele specificate astfel vor fi valabile doar pentru comanda curent: javac - classpath <cale de cautare> <surse java> java - classpath <cale de cautare> <clasa principala> Lansarea n execuie a aplicatiei noastre, din directorul matematica, se va face astfel: java -classpath clase Matematica n concluzie, o organizare eficient a fiierelor aplicaiei ar arta astfel: /matematica /surse /clase compile.bat (javac -sourcepath surse surse/Matematica.java -d clase) run.bat (java -classpath clase Matematica) 3.3.3 Arhive JAR Fiierele JAR (Java Archive) sunt arhive n format ZIP folosite pentru mpachetarea aplicaiilor Java. Ele pot fi folosite i pentru comprimri obinuite, diferena fa de o arhiv ZIP obinuit fiind doar existena unui director denumit META-INF, ce conine diverse informaii auxiliare legate de aplicaia sau clasele arhivate. Un fiier JAR poate fi creat folosind utilitarul jar aflat n distribuia 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; compresare - dimensiunea unei aplicaii n forma sa final este redus; minimizarea timpului de ncarcare a unui applet: dac appletul (fiiere class, resurse, etc) este compresat ntr-o arhiv JAR, el poate fi ncrcat ntr-o singur tranzacie HTTP, fr a fi deci nevoie de a deschide cte o conexiune nou pentru fiecare fiier; securitate - arhivele JAR pot fi semnate electronic mecanismul pentru lucrul cu fiiere JAR este parte integrata a platformei Java. Note

111

112

Programare orientat obiect a) Folosirea utilitarului jar Arhivatorul jar se gsete n subdirectorul bin al directorului n care este instalat kitul J2SDK. Mai jos sunt prezentate pe scurt operaiile uzuale: Crearea unei arhive: jar cf arhiva.jar fiier(e)-intrare Vizualizare coninutului: jar tf nume-arhiva Extragerea coninutului: jar xf arhiva.jar Extragerea doar a unor fiiere: jar xf arhiva.jar fiier(e)-arhivate Executarea unei aplicaii: java -jar arhiva.jar Deschiderea unui applet arhivat: <applet code=A.class archive="arhiva.jar" ...> Exemple: - Arhivarea a dou fiiere class: jar cf classes.jar A.class B.class - arhivarea tuturor fiierelor din directorul curent: jar cvf allfiles.jar * b) Executarea aplicaiilor arhivate Pentru a rula o aplicaie mpachetat ntr-o arhiv JAR trebuie s facem cunoscut interpretorului numele clasei principale a aplicaiei. S considerm urmtorul exemplu, n care dorim s arhivm clasele aplicaiei descrise mai sus, n care clasa principal era Matematica.java. Din directorul clase vom lansa comanda: jar cvf mate.jar geometrie analiza algebra Matematica.class n urma acestei comenzi vom obtine arhiva mate.jar. Dac vom ncerca s lansm n execuie aceast arhiv prin comanda: java -jar mate.jar vom obine urmtoarea eroare: Failed to load Main-Class manifest from mate.jar. Aceasta nseamna c n fiserul Manifest.mf ce se gasete n directorul META-INF trebuie s nregistrm clasa principal a aplicaiei. Acest lucru l vom face n doi pai: se creeaz un fiier cu un nume oarecare, de exemplu manifest.txt, n care vom scrie: Main-Class: Matematica adaugm aceast informaie la fiierul manifest al arhivei mate.jar: jar uvfm mate.jar manifest.txt Ambele operaii puteau fi executate ntr-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 interpretorul Java, ceea ce nseamn c facnd dublu-click pe o arhiv JAR va fi lansat n execuie aplicaia mpachetat n acea arhiv (dac exist o clas principal). 3.3.4 javadoc Javadoc este un instrument foarte util care permite documentarea programelor folosindu-se de comentariile speciale de tip /** comentariu */. n acest fel se poate menine o legtur dinamic ntre program i documentarea sa, mult mai bine dect o legtur static, care poate s nsemne scrierea manual a documentaiei i modificarea ei ori de cte ori apar modificri n program. Utilitarul javadoc extrage n mod automat comentariile din program, ns pe lng aceasta extrage i clasa i metoda creia i aparine comentariul. n felul acesta se poate obine rapid i uor o documentare decent a unui program. Rezultatul este depus ntr-un fiier de tip html. Mai pot fi deasemenea scrise

Note

Programare orientat obiect propriile generatoare de documentare, numite doclets. Observaie: javadoc extrage doar comentariile corespunztoare membrilor de tip public sau protected. Comentariile membrilor de tip private vor fi ignorate. Datorit faptului c rezultatul este depus ntr-un fiier de tip html, este posibil ca n cadrul comentariilor s fie incluse tag-uri de tip HTML. Exemplu: /** * You can <em>even</em> insert a list: * <ol> * <li> Item one * <li> Item two * <li> Item three * </ol> */ Mai exist i o serie de tag-uri specifice utilitarului javadoc care pot fi i ele folosite n cadrul comentariilor: @see, @version, @author, @param, @return, etc. Pentru mai multe detalii despre javadoc se recomand documentaia aferent oferit de site-ul oficial Java. Utilitarul javadoc poate fi folosit att din linia de comand ct i ca i operaie oferit de unele IDE-uri cum ar fi NetBeans i Eclipse (Project-Generate Javadoc).

113

Test de autoevaluare: 1. Care este utilitatea gruprii fiierelor Java?

2. Care este utilitatea importului static?

3. Ce reprezint o cale de cutare (classpath)?

4. Ce este o arhiv jar?

Note

114

Programare orientat obiect

5. Ce se obine cu ajutorul utilitarului javadoc ?

Bibliografie : 1. Cristian Frsinaru Curs practic de Java 2. Bruce Eckel Thinking in Java 4th Edition, Ed. Prentice Hall, 2006, ISBN 0-13-187248-6 3. P. Niemeyer, J. Knudsen - Learning Java 3rd Edition, Ed. OReilly, 2005 4. .Tanas,.Andrei,C. Olaru Java de la 0 la expert, Ed.Polirom, 2007, ISBN 978-973-46-0317-6 5. D.Danciu, G.Mardale - Arta programrii n JAVA (Vol. I) Elemente-suport fundamentale, Ed. Albastr, 2005

Note

Programare orientat obiect Rspunsuri la testele de evaluare Capitolul I. Introducere n Java 1. Principiile de baz ale POO: - Abstractizarea - ncapsularea - Polimorfismul - Motenirea 2. Secvene nelimitate de litere i cifre Unicode, ncepnd cu o liter. 3. int, float, char 4. for, while, do-while 5. String Capitolul II. Elemente de baz ale programarii orientate obiect 2.1 Clase i obiecte 1. constructori, variabile (atribute), metode, clase imbricate 2. Pentru variabilele de clas (statice) sistemul aloc o singur zon de memorie la care au acces toate instanele clasei respective, ceea ce nseamn c dac un obiect modific valoarea unei variabile statice ea se va modifica i pentru toate celelalte obiecte. Cnd declarm o variabil membr fr modificatorul static, la fiecare creare a unui obiect al clasei, sistemul aloc o zon de memorie separat pentru stocarea valorii acelei variabile. 3. class Grupa { int nrPersoane; } class Test{ public static void main (String args[]) { Grupa grupa1=new Grupa(); grupa1.nrPersoane=30; } 4. char tab[]={i,n,f,o}; java.util.Arrays.sort(tab); 5. String sir=informatica; int i=sir.indexOf(a); String sir2=sir.toUpperCase(); 2.2 Motenirea 1. class Matematica { int formula (int x, int y) { return x+y; } int formula (int x) { return 3*x; } } 2. class C1 { int suma (int n1, int n2) { return n1+n2; } }

115

Note

116

Programare orientat obiect class C2 extends C1 { int suma (int n1, int n2) { return 2*n1+3*n2; } } 3. O clas abstract poate conine aceleai elemente membre ca o clas obinuit, la care se adaug declaraii de metode abstracte fr nici o implementare. O clas abstract poate conine metode fr nici o implementare. O clas abstract poate pune la dispoziia subclaselor sale un model complet pe care trebuie s-l implementeze, furniznd chiar implementarea unor metode comune tuturor claselor i lsnd explicitarea altora fiecrei subclase n parte. Interfeele duc conceptul de clas abstract cu un pas nainte prin eliminarea oricror implementri de metode, punnd n practic unul din conceptele programrii orientate obiect i anume cel de separare a modelului unui obiect (interfa) de implementarea sa. O interfa Java definete constante i un set de metode, dar nu specific nici o implementare pentru ele. 4. interface I1 { int suma (int x, int y); } interface I2 { int produs (int m, int n); } class C1 { int nr; void tiparire(int n) { System.out.println(Valoarea=, n); } class C2 extends C1 implements I1, I2 { int suma (int x, int y) { return x+y; } Int produs (int m, int n) { return m*n; } } 5. n cazul n care o interfa conine mai multe metode i, la un moment dat, avem nevoie de un obiect care implementeaz interfaa respectiv dar nu specific cod dect pentru o singur metod, el trebui totui s implementeze toate metodele interfeei, chiar dac nu specific nici un cod. Un adaptor este o clas abstract care implementeaz o anumit interfa fr a specifica cod nici unei metode a interfeei. n situaia cnd avem nevoie de un obiect de tip X vom folosi clasa abstract, supradefinind doar metoda care ne intereseaz. 2.3 Excepii 1. try { // Instructiuni care pot genera exceptii } catch (TipExceptie1 variabila) { // Tratarea exceptiilor de tipul 1

Note

Programare orientat obiect } catch (TipExceptie2 variabila) { // Tratarea exceptiilor de tipul 2 } ... finally { // Cod care se executa indiferent // dac apar sau nu exceptii } 2. Un bloc try si mai multe blocuri catch. 3. throws 4. Erorile sunt cazuri speciale de excepii generate de funcionarea anormal a echipamentului hard pe care ruleaz un program Java i sunt invizibile programatorilor. Un program Java nu trebuie s trateze apariia acestor erori i este improbabil ca o metod Java s provoace asemenea erori. Termenul excepie este o prescurtare pentru eveniment excepional i poate fi definit ca un eveniment ce se produce n timpul execuiei unui program i care provoac ntreruperea cursului normal al execuiei acestuia. Excepiile trebuie tratate de ctre programele Java. 5. Excepiile care pot scpa netratate descind din subclasa RuntimeException i se numesc excepii la execuie. De exemplu exceptia ce poate aparea in cazul impartirii la zero. 2.4 Intrri i ieiri. Fluxuri 1. Fluxurile primitive sunt responsabile cu citirea/scrierea efectiv a datelor, punnd la dispoziie implementri ale metodelor de baz read, respectiv write, definite n superclase. Fluxurile de procesare (sau de filtrare) sunt responsabile cu preluarea datelor de la un flux primitiv i procesarea acestora pentru a le oferi ntr-o alt form, mai util dintr-un anumit punct de vedere. 2. Utilizarea unui buffer n procesul de citire/scriere a informaiilor reduce numrul de accesri la dispozitivul ce reprezint sursa/destinaia original a datelor. Sunt mult mai eficiente dect fluxurile fr buffer i din acest motiv se recomand folosirea lor ori de cte ori este posibil. 3. System.in - fluxul standard de intrare, de tip InputStream System.out - fluxul standard de ieire, de tip PrintStream System.err - fluxul standard pentru erori, de tip PrintStream 4. Scanner s = new Scanner(System.in); String nume = s.next(); int varsta = s.nextInt(); double salariu = s.nextDouble(); 5. Utilitate clasei File const n punerea la dispoziie a unor metode pentru lucrul cu fisiere i directoare la nivelul sistemului de operare. Astfel, n aceast clas se gsesc metode pentru testarea existenei, tergerea, redenumirea unui fiier sau director, crearea unui director, listarea fiierelor dintr-un director, etc. Clasa RandomAccesFile permite accesul nesecvenial (direct) la coninutul unui fiier; implementeaz interfeele DataInput i DataOutput, ceea ce nseamna ca sunt disponibile metode de tipul readXXX, writeXXX, ntocmai ca la clasele DataInputStream i DataOutputStream; permite att citirea ct i scriere din/in fiiere cu acces direct; Note

117

118

Programare orientat obiect 2.5 Colecii 1. Tipul de date al elementelor dintr-o colecie este Object, ceea ce nseamn c mulimile reprezentate sunt eterogene, putnd include obiecte de orice tip. Doar dac se folosesc tipurile generice se vor restriciona tipurile de date ce pot exista la un momentdat ntr-o colecie. 2. List descrie liste (secvene) de elemente indexate. Listele pot contine duplicate i permit un control precis asupra poziiei unui element prin intermediul indexului acelui element. Set modeleaz noiunea de mulime n sens matematic. O mulime nu poate avea elemente duplicate, mai bine zis nu poate conine dou obiecte o1 i o2 cu proprietatea o1.equals(o2). 3. List lst = new ArrayList(); lst.add(new Integer(10)); lst.remove(0); 4. Tipurile generice, introduse n versiunea 1.5 a limbajului Java, simplific lucrul cu colecii, permind tipizarea elementelor acestora. Definirea unui tip generic se realizeaz prin specificarea ntre paranteze unghiulare a unui tip de date Java, efectul fiind impunerea tipului respectiv pentru toate elementele coleciei: <TipDate>. 5. // Parcurgerea elementelor unui vector v for (Enumeration e = v.elements(); e.hasMoreElements();) { System.out.println(e.nextElement()); } Capitolul III. Operatii speciale asupra claselor si obiectelor 3.1 Serializarea obiectelor 1. Serializarea obiectelor se realizeaz prin intermediul fluxurilor definite de clasele ObjectOutputStream (pentru salvare) i ObjectInputStream (pentru restaurare). Metodele pentru serializarea obiectelor sunt: writeObject, pentru scriere i readObject, pentru restaurare. 2. Mecanismul implicit de serializare a unui obiect va salva numele clasei obiectului, signatura clasei i valorile tuturor cmpurile serializabile ale obiectului. 3. Pentru ca un cmp s nu fie salvat n procesul de serializare el trebuie declarat cu modificatorul transient i trebuie s fie nestatic. 4. Object 5. Personalizarea serializarii se realizeaz prin definirea (ntr-o clas serializabil) a metodelor writeObject i readObject avnd exact signatura de mai jos: private void writeObject(java.io.ObjectOutputStream stream) throws IOException private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException 3.2 Fire de execuie 1. Firele de execuie fac trecerea de la programarea secvenial la programarea concurent. Un program secvenial reprezint modelul clasic de program: are un nceput, o secven de execuie a instruciunilor sale i un sfrit. Firele de execuie sunt utile n multe privine, ns uzual ele sunt folosite pentru

Note

Programare orientat obiect executarea unor operaii consumatoare de timp fr a bloca procesul principal: calcule matematice, ateptarea eliberrii unei resurse, desenarea componentelor unei aplicaii GUI, etc. 2. Prin extinderea clasei Thread i supradefinirea metodei run a acesteia sau implementarea interfetei Serializable. 3. Un fir de execuie se poate gsi n una din urmtoarele patru stri: New Thread Runnable Not Runnable Dead 4. Execuia ntr-o anumit ordine a mai multor fire de execuie pe un numr limitat de procesoare se numete planificare (scheduling). Sistemul Java de execuie a programelor implementeaz un algoritm simplu, determinist de planificare, cunoscut sub numele de planificare cu prioriti fixate. Fiecare fir de execuie Java primete la crearea sa o anumit prioritate. Schimbarea ulterioar a prioritii unui fir de execuie se realizeaz cu metoda setPriority a clasei Thread. 5. Exist fire de execuie independente i asincrone, cu alte cuvinte care nu depind n nici un fel de execuia sau de rezultatele altor fire. Exist ns numeroase situaii cnd fire de execuie separate, dar care ruleaz concurent, trebuie s comunice ntre ele pentru a accesa diferite resurse comune sau pentru a-i transmite dinamic rezultatele muncii lor. 3.3 Organizarea claselor 1. Gruparea fiierelor Java pe tipruri (.java, .class) ajut la o mai bun organizare a lor. Orice aplicaie nebanal trebuie s fie construit folosind o organizare ierarhic a componentelor sale. 2. Importul static permite referirea constantelor statice ale unei clase fr a mai specifica numele complet al acesteia i este implementat prin adugarea cuvntului cheie static dup cel de import. 3. O cale de cutare este o list de directoare sau arhive n care vor fi cutate fiierele necesare unei aplicaii. Fiecare director din calea de cautare este directorul imediat superior structurii de directoare corespunztoare numelor pachetelor n care se gsesc clasele din directorul respectiv, astfel nct compilatorul i interpretorul s poat construi calea complet spre clasele aplicaiei. 4. Fiierele JAR (Java Archive) sunt arhive n format ZIP folosite pentru mpachetarea aplicaiilor Java. Ele pot fi folosite i pentru comprimri obinuite, diferena fa de o arhiv ZIP obinuit fiind doar existena unui director denumit META-INF, ce conine diverse informaii auxiliare legate de aplicaia sau clasele arhivate. 5. Javadoc este un instrument foarte util care permite documentarea programelor folosindu-se de comentariile speciale de tip /** comentariu */. n acest fel se poate menine o legtur dinamic ntre program i documentarea sa, mult mai bine dect o legtur static, care poate s nsemne scrierea manual a documentaiei i modificarea ei ori de cte ori apar modificri n program. Utilitarul javadoc extrage n mod automat comentariile din program, ns pe lng aceasta extrage i clasa i metoda creia i aparine comentariul. n felul acesta se poate obine rapid i uor o documentare a unui program. Rezultatul este depus ntr-un fiier de tip html. Note

119

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