CATEGORII DOCUMENTE |
Introducere in programarea orientata pe obiecte
Programarea cu clase si obiecte reprezinta un alt mod de abordare a programarii decat programarea procedurala (in limbaje ca C sau Pascal), cu avantaje in dezvoltarea programelor mari.
Un program procedural (scris in C de exemplu) este o colectie de functii, iar datele prelucrate se transmit intre functii prin argumente (sau prin variabile externe). In programarea procedurala sarcina programatorului este de a specifica actiuni de prelucrare, sub forma de proceduri (functii).
Exemplul urmator este o functie C de copiere a unui fisier, octet cu octet:
// copiere fisier in C
void filecopy ( char * src, char * dst)
Actiunile necesare copierii se realizeaza prin functiile fopen, fgetc, fputc, fclose care primesc ca date variabilele "in", "out" si "ch".
Un program orientat pe obiecte este o colectie de obiecte care interactioneaza prin apeluri de functii specifice fiecarui tip de obiect. In programarea orientata pe obiecte programatorul creeaza obiectele necesare aplicatiei si apeleaza metode ale acestor obiecte pentru actiuni ce folosesc datele continute in obiectele aplicatiei. Exemplul urmator este o functie Java de copiere octeti dintr-un fisier sursa "src" intr-un fisier destinatie "dst":
public static void filecopy (String src, String dst) throws IOException
In acest exemplu se folosesc doua obiecte: un obiect de tip FileReader (prin variabila "in") si un obiect de tip FileWriter (prin variabila "out"); prin metoda "read" se cere obiectului "in" sa citeasca si sa furnizeze un caracter, iar prin metoda "write" se cere obiectului "out" sa scrie in fisier caracterul primit ca argument. Pentru obiectele "in" si "out" se pot apela si alte metode, din clasele respective. Obiectele "in" si "out" contin informatii despre fisierele "src" si "dst" necesare prelucrarii lor, cam aceleasi care se memoreaza intr-o structura de tip FILE in limbajul C. La crearea obiectelor, folosind operatorul new se si deschid cele doua fisiere (actiunea functiei "fopen" din C).
Definitia unei clase poate fi privita ca o extindere a definirii unui tip structura din C, care contine si functii pentru operatii cu datelor continute in clasa. Aceste functii se numesc si metode ale clasei. In Java si in C++ functiile (metodele) sunt subordonate claselor; o metoda poate fi aplicata numai obiectelor din clasa care contine si metoda.
Un obiect corespunde unei variabile structura din C. In C++ o variabila de un tip clasa este un nume pentru un obiect, dar in Java o variabila de un tip clasa contine un pointer catre un obiect (corespunde unei variabile referinta din C++). De aceea, mai corecta este exprimarea 'se apeleaza metoda "read" pentru obiectul adresat prin variabila "in"'. Este posibil ca mai multe variabile de un tip clasa sa contina adresa aceluiasi obiect.
Obiectele Java sunt create dinamic, folosind de obicei operatorul new, care are ca rezultat o referinta la obiectul alocat si initializat printr-o functie constructor, apelata implicit de operatorul new. Eliberarea memoriei se face automat si nu cade in sarcina programatorului Java.
O clasa corespunde unei notiuni abstracte cum ar fi "orice fisier disc", iar un obiect este un caz concret (o realizare a conceptului sau o instantiere a clasei). Un obiect de tip FileReader corespunde unui anumit fisier, cu nume dat la construirea obiectului.
In general, obiecte diferite contin date diferite, dar toate obiectele suporta aceleasi operatii, realizate prin metodele clasei din care fac parte.
Relativ la exemplul Java, trebuie spus ca utilizarea unei functii statice de copiere nu este in spiritul POO. Functiile statice Java corespund functiilor C si pot fi folosite fara ca sa existe obiecte (ele fac parte totusi din anumite clase).
Mai aproape de stilul propriu POO, ar trebui definita o clasa copiator de fisiere, avand si o metoda (nestatica) de copiere, cu sau fara argumente. Exemplu:
public class FileCopier
// o metoda de copiere
public void copy () throws IOException
}
// clasa pentru verificarea clasei FileCopier
class UseFileCopier
}
Clasa "FileCopier", definita anterior, trebuie privita doar ca un prim exemplu, ce trebuia sa fie foarte simplu, si nu ca un model de clasa reala Java.
In exemplele anterioare si in cele ce vor urma se poate observa mutarea accentului de pe actiuni (functii) pe obiecte (date) in programarea orientata pe obiecte. Numele de clase sunt substantive, uneori derivate din verbul ce defineste principala actiune asociata obiectelor respective. In Java exista obiecte comparator (de un subtip al tipului Comparator) folosite in compararea altor obiecte, clasa Enumerator folosita la enumerarea elementelor unei colectii, clasa StringTokenizer folosita la extragerea cuvintelor dintr-un sir s.a.
Clasele sunt module de program reutilizabile
Definirea si utilizarea de module functionale permite stapanirea complexitatii programelor mari si reutilizarea de module prin crearea de biblioteci.
In limbajul C un modul de program este o functie, dar in Java si C++ un modul este o clasa, care reuneste in general mai multe functii in jurul unor date. Utilizarea de clase ca module componente ale programelor are o serie de avanaje fata de utilizarea de functii independente:
- Metodele unei clase necesita mai putine argumente, iar aceste argumente nu sunt modificate in functie; efectul unei metode este fie de a face accesibile date din clasa, fie de a modifica variabile din clasa pe baza argumentelor primite. Variabilele unei clase sunt implicit accesibile metodelor clasei si nu mai trebuie transmise explicit, prin argumente (ca niste variabile externe metodelor, dar interne clasei).
- Solutii mai simple pentru functii al caror efect depinde de stare (de context), cum ar fi de apeluri anterioare ale aceleeasi functii sau ale altor functii pregatitoare.
- Sunt posibile verificari de utilizare corecta a unor metode sau asupra succesiunii de apelare a unor functii; de exemplu nu se poate folosi o metoda de scriere pentru un fisier deschis numai pentru citire sau dintr-o clasa ce permite numai citirea de date.
- O clasa poate incapsula algoritmi de complexitate ridicata, realizati prin colaborarea mai multor functii, unele interne clasei; astfel de algoritmi fie nu sunt disponibili in C, fie sunt disponibili prin biblioteci de functii destul de greu de utilizat. Exemple sunt algoritmi pentru lucrul cu expresii regulate, pentru arhivare-dezarhivare, pentru operatii cu anumite structuri de date (arbori binari cu auto-echilibrare), s.a.
- Se poate realiza un cuplaj mai slab intre module, in sensul ca modificarea anumitor module nu va afecta restul programului. Aceasta decuplare sau separare intre module se poate realiza prin mai multe metode, printre care folosirea de interfete Java, in spatele carora pot sta clase cu implementari diferite dar cu acelasi mod de utilizare.
Existenta unui numar mare de clase predefinite in Java reduce mult timpul de dezvoltare a unor noi aplicatii, prin reutilizarea acestor clase (care trebuie cunoscute, ca posibilitati oferite).
Pentru concretizare vom prezenta solutiile C si Java pentru cateva probleme. Primul exemplu se refera la utilizarea structurii de tip stiva ("stack") in aplicatii. O stiva poate fi realizata fie printr-un vector, fie printr-o lista inlantuita, dar operatiile cu stiva sunt aceleasi, indiferent de implementare: pune date pe stiva, scoate datele din varful stivei si test de stiva goala.
In limbajul C se pot defini functiile pentru operatii cu stiva astfel ca utilizarea lor sa nu depinda de implementarea stivei, prin folosirea unui pointer la o structura:
void initSt ( Stiva * sp); // initializare stiva
int emptySt (Stiva * s); // test stiva goala
int push (Stiva * sp, T x); // pune in stiva un element de tip T
T pop (Stiva * sp ); // scoate din stiva un element de tip T
Definitia tipului "Stiva" si definitiile functiilor depind de implementare.
Un exemplu de utilizare a unei stive:
#include 'stiva.h'
#define T int
void main ()
Modificarea tipului de stiva necesita un alt fisier "stiva.h" si o alta biblioteca de functii (push, pop), care sa fie folosita impreuna cu programul de utilizare a stivei.
In Java acelasi program de exersare a operatiilor cu stiva arata astfel:
public static void main (String arg[ ])
Modificarea implementarii stivei, prin definirea unei alte clase "Stack" nu necesita modificari in functia anterioara, ci doar punerea noii clase in caile de cautare ale compilatorului si interpretorului Java. In plus, modificarea tipului datelor puse in stiva necesita modificari mai mici in Java decat in C.
Un al doilea exemplu este cel al extragerii de cuvinte succesive dintr-un sir de caractere ce poate contine mai multe cuvinte, separate prin anumite caractere date.
Problema este aceea ca dupa fiecare cuvant extras se modifica adresa curenta in sirul analizat, deci starea sau contextul in care se executa functia ce da urmatorul cuvant.
In limbajul C se pot intalni mai multe solutii ale acestei probleme in diferite functii de biblioteca:
Functia "strtok" se foloseste relativ simplu, dar pretul platit este modificarea sirului analizat si imposibilitatea de a analiza in paralel mai multe siruri (pentru ca adresa curenta in sirul analizat este o variabila statica interna a functiei). In plus, primul apel difera de urmatoarele apeluri ale functiei. Exemplu:
cuv=strtok(str, sep); // primul cuvant din "str", sep= sir de separatori
while (cuv !=NULL)
Functia "strtod" extrage urmatorul numar dintr-un sir si furnizeaza adresa imediat urmatoare numarului extras. Exemplu de utilizare:
char * p = str; double d; // str = sir analizat
do while (d != 0); // d=0 cand nu mi exista un numar corect
In Java exista clasa de biblioteca StringTokenizer, folosita dupa cum urmeaza:
String sep = new String (' ,.;nt'); // lista separatori de cuvinte
StringTokenizer st = new StringTokenizer (sir,delim); // "sir" = sir analizat
while (st.hasMoreTokens())
La crearea unui obiect StringTokenizer se specifica sirul analizat, astfel ca se pot analiza in paralel mai multe siruri, pentru fiecare folosind un alt obiect. Metodele "nextToken" si "hasMoreTokens" folosesc in comun o variabila a clasei care contine pozitia curenta in sirul analizat (initializata cu adresa sirului, la construirea obiectului).
In prelucrarea fisierelor apar situatii cand executia cu succes a unei functii depinde de folosirea anterioara a altor functii (cu anumite argumente); de exemplu pentru a putea scrie intr-un fisier, acesta trebuie anterior deschis pentru creare sau pentru adaugare (extindere fisier existent). O situatie asemanatoare apare la utilizarea unor functii care compun o interfata grafica si care trebuie folosite intr-o anumita ordine. Astfel de conditionari reciproce nu se pot verifica automat in C, fiind vorba de functii independente. In Java operatiile sunt metode dintr-o aceeasi clasa si se poate verifica printr-o variabila a clasei succesiunea corecta de folosire a metodelor.
Functionalitatea unei clase poate fi reutilizata in alte clase fie prin derivare, fie prin agregare (compunere). In acest fel, operatiile necesare intr-o clasa sunt fie mostenite de la o alta clasa, fie delegate spre executie metodelor unei alte clase. De exemplu, extinderea automata a unui vector, necesara uneori dupa adaugarea la vector, este refolosita si intr-o clasa stiva vector, fie prin definirea clasei stiva ca o clasa derivata din vector, fie prin folosirea unei variabile Vector in clasa stiva.
In POO adaptarea unei clase la cerinte specifice unor aplicatii nu se face prin interventie in codul clasei ci prin derivare sau prin delegare, tehnici specifice POO.
O interfata contine una sau mai multe operatii (metode abstracte) cu rol bine definit, dar a caror implementare nu poate fi precizata. Cel mai simplu exemplu din Java este interfata Comparator, cu o singura metoda "compare", pentru compararea a doua obiecte (dupa modelul comparatiei de siruri din C). Pentru fiecare tip de obiecte (comparabile) va exista o alta definitie a functiei "compare".
O interfata cu o singura metoda corespunde unui pointer la o functie din limbajul C, dar interfetele cu mai multe metode creeaza posibilitati inexistente in C. O interfata poate fi implementata de mai multe clase, toate cu acelasi rol dar cu mod de lucru diferit. Interfata Collection defineste cateva operatii ce trebuie sa existe in orice colectie de obiecte, indiferent de structura colectiei: adaugare obiect la colectie s.a.
O clasa creeaza un spatiu de nume pentru metodele clasei: pot exista metode cu acelasi nume (si aceleasi argumente) in clase diferite. Pachetul de clase ("package") este o alta unitate Java care creeaza un spatiu de nume pentru clasele continute in el.
O notiune proprie programarii cu obiecte este notiunea de componenta software. Ideea este de a obtine rapid un prototip al aplicatiei fara a scrie cod sau cu un minim de programare, prin asamblarea de componente prefabricate (in special pentru interfata grafica, dar nu numai).
O componenta poate contine una sau mai multe clase si poate fi reutilizata si adaptata fara interventie in codul sursa al componentei (care nici nu este disponibil).
O componenta JavaBeans poate fi (re)utilizata fara a scrie cod, prin generarea automata a operatiilor de instantiere, de modificare a proprietatilor si de conectare cu alte clase (prin apeluri de metode sau prin evenimente), in urma unor comenzi date de utilizator unui mediu vizual de dezvoltare a aplicatiilor. O componenta este de obicei o clasa care respecta anumite conditii.
Clasele creeaza noi tipuri de date
In limbajul C, prin definirea de tipuri structura, se pot defini noi tipuri de date ca grupuri de variabile de alte tipuri predefinite. De exemplu, vom defini o structura cu doua variabile (parte reala, parte imaginara) pentru un numar complex:
typedef struct Complex ;
In Java, introducerea unui tip "Complex" se va face prin definirea unei clase, care va specifica si operatiile permise cu date de acest tip, precum si modul de construire a obiectelor de tip "Complex" (de initializare a partii reale si partii imaginare).
Multe din clasele de biblioteca Java pot fi privite ca avand drept scop extinderea limbajului cu noi tipuri de date, utile in mai multe aplicatii. Exemple: BigInteger, BigDecimal, String, Date etc. Pentru fiecare tip primitiv de date exista un tip clasa asociat: Integer, Short, Long, Float, Double, Boolean, Character.
Cel mai folosit tip de date definit printr-o clasa este tipul String; un obiect de tip String contine ca date un vector de caractere si lungimea sa si suporta un numar mare de metode ce corespund unor operatii uzuale cu siruri (realizate prin functii de biblioteca in limbajul C). Exemple de metode des folosite din clasa String:
int length (); // lungimea acestui sir (pentru care se apeleaza metoda)
boolean equals (String s); // comparatie la egalitate de siruri
int compareTo (String s); // comparatie de siruri cu acelasi rezultat ca "strcmp" (C)
char charAt (int i); // caracterul din pozitia 'i' a acestui sir
int indexOf (char c); // indicele (pozitia) caracterului 'c' in acest sir
int indexOf (String s); // indicele (pozitia) sirului 's' in acest sir (prima aparitie)
String substring(int i); // extrage din acest sir subsirul care incepe in pozitia 'i'
String substring(int i, int j); // extrage subsirul dintre pozitiile 'i' si 'j'
De observat ca operatiile de comparatie (si alte metode) au un singur argument desi compara doua obiecte sir: obiectul pentru care se executa metoda si obiectul primit ca argument. Vom citi un apel de metoda de forma a.compareTo(b) astfel: compara acest obiect ('a') cu obiectul 'b'.
Noile tipuri de date se pot folosi in declaratii de variabile, de functii, de argumente de functii. Exemplu de functie statica care foloseste metodele "indexOf", "length" si "substring" din clasa String
// inlocuire repetata in sirul s a subsirului s1 prin sirul s2
public static String replaceAll (String s, String s1, String s2)
return s; // are ca rezultat sirul modificat prin inlocuire
}
Utilizatorii isi pot defini propriile clase, pentru tipuri de date necesare aplicatiilor; de exemplu, putem defini o clasa "BoolMatrix" pentru o matrice cu elemente de tip boolean. In Java orice clasa este automat derivata dintr-o clasa generica Object si, ca urmare, trebuie sa redefineasca anumite metode mostenite: "toString", "equals" s.a.
Exemplu de clasa minimala pentru o matrice de biti:
// matrice cu elemente de tip boolean
public class BoolMatrix
// modifica valoare element
public void setElement (int i,int j, boolean b)
// citire valoare element
public boolean getElement (int i,int j)
// sir cu elementele din matrice
public String toString ()
return s;
}
// exemplu de utilizare
public static void main (String arg[])
}
Variabilele dintr-o clasa sunt declarate de obicei cu atributul private, ceea ce le face inaccesibile pentru metode din alte clase. Se mai spune ca datele sunt ascunse sau sunt incapsulate in fiecare obiect. Metodele clasei sunt de obicei publice pentru a putea fi apelate din alte clase.
Deoarece datele dintr-un obiect (variabile private) nu sunt direct accesibile din afara clasei si pot fi modificate numai prin intermediul metodelor clasei, utilizarea tipurilor de date definite prin clase este mai sigura decat a celor definite prin structuri. De exemplu, orice modificare a vectorului de caractere dintr-un obiect StringBuffer (StringBuilder) este insotita de modificarea lungimii sirului (in metodele care pot modifica lungimea sirului), dar lungimea nu poate fi modificata direct de catre functii din alte clase (si nici continutul vectorului de caractere).
In Java nu se pot supradefini operatori, deci operatiile cu noile tipuri de date se pot exprima numai prin metode asociate obiectelor (metode nestatice).
Tipurile de date definite prin clase pot forma ierarhii de tipuri compatibile (care se pot inlocui prin atribuire sau la transmitere de argumente).
Clasele permit programarea generica
Programarea generica ne permite sa avem o singura clasa pentru un vector (sau pentru o lista), indiferent de tipul datelor care vor fi memorate in vector (in lista). Tot programarea generica ne permite sa folosim o singura functie (metoda) pentru a parcurge elementele oricarei colectii (indiferent de structura ei fizica ) sau pentru a ordona orice lista abstracta (o colectie care suporta acces direct prin indice la orice element din colectie).
Genericitatea colectiilor de obiecte poate fi realizata in limbajele cu clase prin doua metode:
- prin colectii ce contin un supertip al tuturor tipurilor clasa (tipul Object in Java);
- prin clase ce au ca parametri tipurile de date folosite (numite "templates" in C++).
Colectiile cu elemente de tip Object au existat de la inceput in Java, iar colectiile cu tipuri de date ca parametri au aparut din versiunea 5 si sunt numite generice ("generics").
Pentru a permite colectii cu date de orice tip limbajul Java considera ca toate clasele predefinite sau care urmeaza a fi definite de utilizatori sunt implicit derivate dintr-o clasa Object, care este radacina ierarhiei de clase Java. Tipul unei clase derivate este subtip al tipului clasei din care deriva, asa cum tipul int poate fi considerat ca un subtip al tipului long, iar tipul float ca un subtip al tipului double. La fel cum un argument formal de tip double poate fi inlocuit cu un argument efectiv de tip int, tot asa un argument formal de un tip clasa B poate fi inlocuit cu un argument efectiv de un tip clasa D; clasa D fiind derivata din clasa B. In felul acesta se pot scrie functii generice, cu argumente de un tip general si utilizabile cu o multitudine de tipuri de argumente (asa cum functia "sqrt" se poate apela cu argument de orice tip numeric din C).
O colectie de variabile de tip Object poate contine referinte la obiecte de orice tip, pentru ca acestor variabile li se pot atribui variabile de orice alt tip clasa (care contin adresele unor obiecte). Este la fel cum in limbajul C un vector de pointeri de tip void* poate fi folosit pentru a memora adrese ale unor date (alocate dinamic) de orice tip predefinit sau definit de utilizatori; adaugarea la vector a unui pointer oarecare nu necesita o conversie, dar la extragerea din vector trebuie trecut de la tipul void* la tipul de pointer folosit la adaugare (prin operatorul de conversie de tip "cast").
Exemplu de calcul a sumei valorilor unor obiecte numerice dintr-un vector:
Vector v = new Vector(); // creare obiect vector (extensibil)
for (int k=1; k<11; k++) // genereaza numerele 1,2.3. 10
v.add ( new Integer(k)); // adauga numarul k la vector ca obiect de tip Integer
int sum=0;
for (int k=0;k<v.size();k++)
Conversia in sus de la subtipul Integer la supertipul Object se face automat (argumentul metodei "add" este de tip Object), dar conversia in jos (de la Object la Integer, pentru rezultatul metodei "get") trebuie ceruta in mod explicit prin operatorul de conversie ( ca si in C).
O colectie Java generica specifica tipul obiectelor continute inca de la declarare (care poate fi orice subtip de Object sau de alt tip), iar la extragere nu mai trebuie facuta nici o conversie de tip. Acelasi exemplu dinainte cu colectii generice:
Vector <Integer> v = new Vector<Integer>(); // creare obiect vector de Integer
for (int k=1; k<11; k++) // genereaza numerele 1,2.3. 10
v.add ( new Integer(k)); // adauga numarul k la vector ca obiect de tip Integer
int sum=0;
for (int k=0;k<v.size();k++)
sum += v.get(k).intValue();
O alta simplificare privind utilizarea colectiilor generice de tipuri ce corespund tipurilor primitive (Byte, Short, Integer, Float, Double, Boolean, Character) este trecerea automata de la tipul primitiv la tipul clasa corespunzator ("autoboxing") si trecerea inversa ("unboxing"). Exemplu reluat:
Vector <Integer> v = new Vector<Integer>(); // creare obiect vector de Integer
for (int k=1; k<11; k++) // genereaza numerele 1,2.3. 10
v.add ( k); // conversie automata de la "int" la "Integer"
int sum=0;
for (int k=0;k<v.size();k++)
sum += v.get(k); // conversie automata de la "Integer" la "int"
Clasele creeaza un model pentru universul aplicatiei
Un program destinat unei aplicatii trebuie sa transforme notiunile si actiunile specifice aplicatiei in constructii specifice limbajului de programare folosit (functii, variabile, argumente de functii, etc.).
Evolutia limbajelor de programare poate fi privita si ca un progres al abstractizarii, in sensul indepartarii progresive de masina fizica prin introducerea de notiuni tot mai abstracte. Fiecare limbaj de programare ofera programatorilor o masina virtuala (sau abstracta ) diferita de masina concreta pe care se vor executa programele lor.
Programarea orientata pe obiecte permite definirea de clase si obiecte ce corespund direct obiectelor din universul aplicatiei si modelarea relatiilor statice si dinamice dintre aceste obiecte. Identificarea obiectelor si actiunilor specifice unei aplicatii se face in faza de analiza orientata obiect a problemei de rezolvat si implica o abordare diferita de cea anterioara.
Un program Java poate fi privit ca o descriere a unor obiecte si a interactiunilor dintre aceste obiecte. Intr-un program Java nu exista altceva decat obiecte si clase. Analiza orientata pe obiecte poate incepe cu o descriere in limbaj natural a ceea ce trebuie sa faca programul; substantivele din acest text corespund in general unor obiecte (clase), iar verbele din text corespund unor metode. O astfel de abordare este potrivita pentru aplicatii grafice, pentru jocuri, pentru aplicatii bancare s.a.
Multe aplicatii folosesc o interfata grafica cu utilizatorii (operatorii) aplicatiei; obiectele vizuale afisate pe ecran si care pot fi selectate sau actionate de operator (ferestre, butoane, meniuri, casete cu text, s.a.) corespund direct unor obiecte din programele Java.
Intr-o aplicatie bancara vor exista clase si obiecte de genul "Account" (cont bancar) si "Customer" (client al bancii). Un obiect "Customer" va contine date de identificare ale clientului si metode pentru obtinerea sau modificarea acestor date. Un obiect de tip "Account" va contine suma din cont (si alte date asupra operatiilor cu acel cont), precum si metode pentru depunerea de bani in cont, pentru retragerea de bani din cont si pentru vizualizarea sumei de bani din cont.
Obiectele de tipul "Account" sau "Customer" se numesc si obiecte din domeniul aplicatiei ("domain objects"). Aplicatiile mai pot contine obiecte ajutatoare ("helper") sau obiecte din clase predefinite pentru operatii cu anumite tipuri de date, cu colectii de obiecte, cu baze de date, cu conexiuni intre calculatoare s.a.
Vectori intrinseci si obiecte vector
In Java coexista vectorii mosteniti din limbajul C (ca tip de date predefinit si recunoscut de compilator) cu obiecte din clasele de biblioteca Vector sau ArrayList. Fiecare solutie de grupare a unor date are avantaje si dezavantaje si de aceea unele metode din clase de biblioteca au ca rezultat sau primesc vectori intrinseci iar altele obiecte Vector. Pentru clasa JList exista constructor cu argument Vector dar si constructor cu argument Object[]. Orice clasa colectie (deci si clasa Vector) contine o metoda "toArray" care produce un vector intrinsec cu obiectele din colectie.
Un vector intrinsec ocupa mai putina memorie, accesul la elementele vectorului este mai rapid si nu necesita conversie prin "cast", ca in cazul obiectelor Vector. Intr-un astfel de vector se pot memora si date de un tip primitiv. Se recomanda atunci cand vectorul nu isi mai modifica continutul si este doar folosit. Exemple:
- Metoda "split" din clasa String (din versiunea 4) produce un vector cu toate cuvintele dintr-un sir dat: String[] split (String regexp)
- Metodele "list" si "listFiles" din clasa File produc un vector cu toate fisierele dintr-un director dat: File[] listFiles();
Obiectele din clasa Vector asigura extinderea automata a unui vector (realocarea dinamica pentru marirea capacitatii) la operatii de adaugare si au o multime de metode pentru operatii uzuale cu vectori: obtinerea numarului de elemente, cautarea unui obiect dat, eliminarea de elemente, s.a. Exemple de metode utilizate frecvent:
int size( ); // dimensiunea acestui vector (nr de elemente)
boolean contains (Object obj); // daca acest vector contine obiectul obj
int indexOf (Object obj); // prima pozitie unde se afla obiectul obj sau -1
int indexOf (Object obj, int i); // prima pozitie de dupa i unde se afla obiectul obj
int lastIndexOf (Object obj); // ultima pozitie din acest vector unde se afla obj
Object elementAt (int i); // obiectul din pozitia i din acest vector
Object get(int i); // obiectul din pozitia i din acest vector
boolean add (Object obj); // adauga obj la sfarsitul acestui vector
void addElement (Object obj); // adauga obj la sfarsitul acestui vector
void insertElementAt (Object obj, int i); // introduce obj in pozitia i din vector
boolean remove (Object obj); // elimina elementul cu valoarea obj din vector
Object remove (int i); // elimina elementul din pozitia i din acest vector
void setElementAt (Object obj, int i); // inlocuieste elementull din pozitia i cu obj
Object[] toArray(); // produce un vector intrinsec cu aceleasi elemente
String toString(); // produce un sir cu elementele din vector, ca siruri
Existenta unor metode diferite cu acelasi efect se explica prin faptul ca din versiunea 2 clasa Vector a fost modernizata pentru compatibilizare cu interfata List si a fost adaugata clasa ArrayList, care are aceeasi functionalitate cu clasa Vector.
Clasa Vector contine un vector intrinsec de elemente de tip Object, plus variabile pentru capacitatea alocata si pentru dimensiunea efectiva a vectorului. Se recomanda pentru vectori de obiecte cu continut variabil (in decursul executiei programului).
Pentru comparatie vom scrie doua functii similare functiei "split", dar care nu foloseste expresii regulate pentru extragere de cuvinte dintr-un sir (cuvintele sunt separate intre ele printr-un numar oarecare de spatii albe):
class Unu
// utilizare functie
public static void main (String arg[])
}
import java.util.Vector;
class Doi
// utilizare functie
public static void main (String arg[])
Afisarea continutului unui obiect Vector (ca si afisarea continutului oricarei colectii) este simplificata de existenta metodei "toString". Metoda "println" cu argument Object foloseste automat metoda "toString" pentru obiectul respectiv:
System.out.println (w.toString()); // la fel cu: System.out.println(w);
Incepand din versiunea 5 se poate preciza tipul elementelor din vector, pentru clasa Vector, ca si pentru orice alta clasa colectie, folosind ceea ce se numeste un vector generic. Exemple de functie care determina sirul de lungime maxima dintr-un vector de siruri, in doua variante:
// inainte de Java 5
public static String maxLen (Vector v)
return sm;
}
// Java 5 si 6
public static String maxLen2 (Vector<String> v)
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 998
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved