Sunteți pe pagina 1din 9

Programare generica Programarea generica a fost introdusa in J2SE 5.

0 si modifica semnificativ sintaxa limbajului facand codul mult mai sigur din punct de vedere al tipului de date (type safe . Programarea generica foloseste parametri cu tip atunci cand defineste clase sau metode. !odul generic este inrudit cu tipurile parametri"ate sau template#urile. Programarea generica inlatura necesitatea conversiei de tip$ cu avantaje substantiale pentru programatori si pentru procesul de debugging. %stfel$ multe dintre erorile de executie sunt detectate inca din fa"a de compilare. !odul non#generic este denumit cod legacy.
// Legacy Code List list = new ArrayList(); //Generic Code List<Integer> list = new ArrayList<Integer>();

&n exemplul anterior ambele linii crea"a o lista de obiecte. Prima cre"a un sir ce accepta orice tip de obiect. %ceasta inseamna ca anumite metode ale clasei ArrayList necesita conversie manuala ceea ce poate conduce la aparitia erorilor la executie. &n cea de#a doua linie am folosit cod generic. 'ipul elementelor sirului a fost scris intre semnele <> si determina ca toate elementele sa fie de tip Integer. %vantajele folosirii tipului generic sunt( !olectiile generice stoc)ea"a numai tipuri cunoscute Erorile de tip sunt prinse inca in fa"a de compilare &n majoritatea ca"urilor elimina nevoia de conversie !odul este mai usor de inteles 'impul de executie este scurtat Este usor de trecut de la legacy la generic si invers pentru ca exista bac*+ard compatibilty intre generic si legacy ,e"vantaje( !odul generic e greu de de"voltat !odul generic e greu de interpretat -rmatorul exemplu ilustrea"a producerea unei erori la executie din cau"a folosirii defectoase a tipului ro+ (legacy code . Elementele listei se considera de tip Object. Eroare nu a fost identificata la compilare. &n versiuni mai mari de 5$ avem atentionari in ceea ce priveste folosirea tipului ro+.

import java !til "; public class Generic#rror $ public static void %ain(&tring'( args) $ // )*is list is not ty+e sa,e- as it can store any ty+e o, object List list = new ArrayList(); list add(.); list add(/0/); for (Iterator i = list iterator(); i *as1e2t();) $ // !r%atoarea linie va genera o eroare la r!lare relativ la conversia string3!l!i /0/ in Integer int val!e = ((Integer) i ne2t()) " 45; &yste% out +rintln(val!e); 6 6 6

Solutia este(

import java !til "; public class Generic7i2 $ public static void %ain(&tring'( args) $ // lista va ,i declarata de ti+ Integer List<Integer> list = new ArrayList<Integer>(); list add(.); list add(/0/); for (Iterator<Integer> i = list iterator(); i *as1e2t();) $ int val!e = (i ne2t()) " 45; &yste% out +rintln(val!e); 6 6 6

in care primim eroarea de incompatibilitatea a tipurilor inca din fa"a de compilare. !ompilatorul foloseste un proces numit erasure sau type erasure pentru a asigura faptul ca codul generic este compatibil cu codul legacy$ de aceea cele doua tipuri de cod pot fi folosite simultan.
class A8C<)>$ // declara !n obiect de ti+ ) ) obj; // constr!ctor!l A8C () aObj) $ obj = aObj 6 // o %etoda ce ret!rnea9a obj ) getObj()$ ret!rn obj; 6

&n aceasta clasa generica procesul de compilare este urmatorul( tipul parametri"at generic$ )$ este indepartat si inlocuit de tipul corespun"ator prin eventuale conversii. ,aca nu se specifica niciun tip atunci se foloseste tipul Object pentru a asigura compatibilitatea cu alte clase. ,efinirea unui tip generic se face dupa urmatoarea sintaxa(
class n!%e<lista:+ara%etri:generici>$ 6

Sintaxa poate fi aplicata si interfetelor sau oricaror tipuri container din ierar)ia Collection precum( List$ ;a+$ etc. Poate fi aplicata$ de asemenea$ constructorilor sau metodelor unei clase. Parametrii sunt intotdeauna tipuri clasa. &ata cateva exemple(
+!blic inter,ace<)>$ void add() e); 6 List<Acco!nt> list = new ArrayList<Acco!nt>(); ;a+<Integer- &tring> level = new <as*;a+<Integer- &tring>();

Putem defini metode generice in interiorul claselor generice si putem defini clase generice ce extind clase generice sau nongenerice. -rmatorul cod va genera eroare la atribuire din cau"a incompatibilitatii tipurilor.
class Gen<)y+e> $ // diverse %etode; 6

class Gen)est $ public static void %ain(&tring'( args) $ // initiali9area instantelor claselor generice Gen

Gen<Integer> A = new Gen<Integer>(); Gen<&tring> 8 = new Gen<&tring>(); 6 6 A = 8; //eroare=

Putem folosi colectii generice. %cestea pot fi declarate cat si intiali"ate ca generice. ,aca o colectie este initiali"ata ca generica$ dar nu are o declaratie generica atunci ea va accepta obiecte arbitrare. %ceasta este ilustrat in exemplul urmator(
List list =new ArrayList<Integer>(); list add(.); list add(/0/);

%peluri ca( sunt posibile$ dar vor genera atentionari la compilare. .a executie$ insa$ urmatoarea sintaxa va genera eroare(
for (Iterator<Integer> i = list iterator(); i *as1e2t();) $ int val!e = (i ne2t()) " 45; &yste% out +rintln(val!e); 6 / restricie fundamentala in ca"ul programarii generice este ca un tip generic ) nu este compatibil cu Object. %stfel$ nu putem face atribuirea List<)> la un List<Object>.

0otivatia vine din faptul ca un obiect de orice tip ar putea fi inserat in lista.
public class Generic $ public static void %ain(&tring'( args) $ List<Acco!nt> list = new ArrayList<Acco!nt>(); //desi Acco!nt e2tinde Object- o lista Acco!nt n! +oate // ,i atrib!ita !nei liste Object List<Object> objects = list;

6 6

'ipul identic cu codul legacy List. &n anumite situatii trebuie sa facem conversii explicite cand utili"am tipuri generice. !a"ul cel mai frecvent este atunci cand folosim obiecte instante ale unor clase derivate din clasa declarata ca parametru. -n exemplu este in cele ce urmea"a(
public class Generic $ public static void %ain(&tring'( args) $ List<Acco!nt> list = new ArrayList<Acco!nt>(); // Ada!garea !n!i ele%ent dintr3o clasa derivata din Acco!nt list add(new ;ortgage()); // cand e2trage% ele%ent!l treb!ie sa ,ace% !n cast ;ortgage %ortgage = (;ortgage) list get(5); 6 6 class Acco!nt $ 6 class ;ortgage extends Acco!nt $ 6

class Acco!nt $ 6 List<Object> este practic

Putem adauga si liste intregi intre elementele unei liste existente$ ca" ilustrat mai jos(
import java !til "; public class Generic$ public static void %ain(&tring'( args) $ List<;ortgage> %ortgageList = new ArrayList<;ortgage>(); %ortgageList add(new ;ortgage()); List<>e+osit> de+ositList = new ArrayList<>e+osit>();

6 6 class Acco!nt $ 6 class ;ortgage extends Acco!nt $ 6 class >e+osit extends Acco!nt $ 6

de+ositList add(new >e+osit()); List<Acco!nt> acco!ntList = new ArrayList<Acco!nt>(); acco!ntList addAll(%ortgageList); acco!ntList addAll(de+ositList);

,aca adaugarea a fost posibila$ in ca"ul extragerii vom avea nevoie de cast. %tribuirea directa nu este posibila$ asa precum am aratat anterior. -rmatorul cod generea"a eroare la compilare(
acco!ntList=%ortgageList;

Solutia pentru atribuirea subtipului unui supertip este folosirea sintaxei( <? e2tends Acco!nt>. ? poarta denumirea de +ildcard. !odul din exemplul anterior se modifica$ pentru atribuire$ dupa cum urmea"a(
import java !til "; public class Generic $ public static void %ain(&tring'( args) $ List<;ortgage> %ortgageList = new ArrayList<;ortgage>(); %ortgageList add(new ;ortgage()); List<? extends Acco!nt> list = %ortgageList; list = %ortgageList;

6 6 class Acco!nt $ 6 class ;ortgage extends Acco!nt $ 6

Codul generic - tipul bounded 'ipurile bounded nu exista in ca"ul codului legacy. 'oate obiectele in cod legacy sunt implicit marginite superior de Object. %stfel$ orice metoda poate accepta orice tip de obiect$ ceea ce determina folosirea conversiei pentru a incerca prevenirea exceptiilor. &n sc)imb$ tipurile generice elimina conversiile$ dar aceasta introduce o limitare si anume tipurile generice nu pot fi specificate. Presupunem ca dorim sa cream o clasa ce returnea"a suma$ ca un do!ble$ a unui sir de numere de oricare dintre tipurile( int$ do!ble sau ,loat. %ceasta ar insemna crearea a trei clase cu cod aproape identic.
class &!%<Integer> $ // calc!larea s!%ei 6 class &!%<7loat> $ // calc!larea s!%ei 6 class &!%<>o!ble> $ // calc!larea s!%ei 6

&n Java 5.0 se introduce tipul bounded pentru a elimina acest neajuns. Sintactic$ in programarea generica$ tipul bounded este folosit in sintaxa <) e2tends s!+erclasa>$ unde ) poate fi orice subtip al superclasei sau c)iar superclasa (superclasa este de tip bounded . &n ca"ul presupunerii nostre Integer$ 7loat si >o!ble sunt toate subclase ale clasei 1!%ber$ care este clasa de tip bounded.
public class &!%<) extends 1!%ber> $ )'( n!%s; // n!%s este !n sir de ti+ 1!%ber sa! s!bclasa a sa

// constr!ctor &!% ()'( o)$ n!%s = o; 6 // ti+!l ret!rnat este do!ble in oricare dintre ca9!ri double s!%)otal() $ double s!% = 5 5; for (int i=5; i < n!%s lengt*; i@@) s!% @= n!%s'i( do!bleAal!e(); 6 return s!%;

public static void %ain(&tring'(args)$ Integer a'(=$4-B-C6; >o!ble d'(=$D 5-. 5-E 56; &!%<Integer> intregi=new &!%<Integer>(a); &yste% out +rintln(intregi s!%)otal()); &!%<>o!ble> reali=new &!%<>o!ble>(d); &yste% out +rintln(reali s!%)otal()); 6

!lasa 1!%ber se numeste bounded si compilatorul stie ca obiectele de tip ) pot apela orice metoda declarata de 1!%ber. &n plus$ compilatorul va preveni crearea oricaror obiecte &!% fara a fi numerice (instanta a lui 1!%ber sau derivate din aceasta . Presupunem$ in continuare$ ca dorim sa comparam sumele calculate in doua clase &!%. Pentru aceasta am definit in clasa &!% metoda &tring co%+are( &!%<)>). %ceasta$ insa$ ridica o problema deoarece &!%<Integer> nu poate fi comparata cu &!%<1!%ber>$ c)iar daca Integer este subtip al lui 1!%ber. Pentru re"olvarea acestei probleme Java face apel la elementul ? (+ildcard $ ce specifica un tip necunoscut. !u acesta semnatura metodei devine( &tring co%+are( &!%<?>) si acum accepta orice tip de obiect &!%. !odul$ cu adaugarea acestei metode devine(
public class &!%<) extends 1!%ber> $ )'( n!%s; // n!%s este !n sir de ti+ 1!%ber sa! s!bclasa a sa // constr!ctor &!% ()'( o)$ n!%s = o; 6 // ti+!l ret!rnat este do!ble in oricare dintre ca9!ri double s!%)otal() $ double s!% = 5 5; for (int i=5; i < n!%s lengt*; i@@) s!% @= n!%s'i( do!bleAal!e(); return s!%; 6 &tring co%+arare(&!%<?> ob)$ if (this s!%)otal()<ob s!%)otal()) return /%ai %ic/; else return /%ai %are sa! egal/; 6

public static void %ain(&tring'(args)$ Integer a'(=$4-B-C6; >o!ble d'(=$D 5-. 5-E 56; &!%<Integer> intregi=new &!%<Integer>(a); &yste% out +rintln(intregi s!%)otal()); &!%<>o!ble> reali=new &!%<>o!ble>(d); &yste% out +rintln(reali s!%)otal()); &yste% out +rintln(intregi co%+arare(reali)); 6

Si cu +ildcardurile putem folosi tipurile marginite (bounded intr#o sintaxa de tipul <? e2tends s!+erclasa>. !onventie( putem folosi ce identificatoare dorim$ dar urmatoarele sunt deseori foarte sugestive( # )( 'ype # #( Element # F( 1ey # A( 2alue # &$ G( utili"ati ca al doilea tip$ al treilea$ etc. &n Java SE 3 nu este nevoie sa repetam tipurile in partea dreapta a unei instructiuni. Parante"ele ung)iulare simple indica ca parametrii de tip sunt aceeasi. Ex( List <Integer> l = new ArrayList<>(); !a bune practici adaugarea unui element intr#o colectie ar trebui facuta printr#o metoda cu semnatura(
<)> void addIte%() a- Collection<)> c);

!opierea a doua liste ar trebui facuta folosind metode cu semnatura(


<)> void co+y(List<)> dest- List<? e2tends )> src);

Sau intr#un mod fara +ild card(


<)- & e2tends )> void co+y(List<)> dest- List<&> src); Sintaxa ? s!+er ) denota un tip necunoscut ce este supertip al lui )

si se numeste lo+er

bound. Lint warnings .int repre"inta o functionalitate a Javei ce ne permite sa identificam cod nesigur. .int +arnings se generea"a cand incercam sa compilam cod nesigur. 4ecompilarea unui cod cu HIlintJ!nc*ecKed$ va genera avertismentele de cod nesigur indicand locul in care pot aparea erori la executie. Declararea unei clase generice !and declaram o clasa generica trebuie sa furni"am parametrul tip. !lasa generica se va executa indiferent de tipurile parametru transmise. !and cream o instanta a unui tip generic$ argumentul tip transmis parametrului tip trebuie sa fie tip clasa. class1a%e<lista3arg3ti+> var1a%e= new class1a%e<lista3arg3 ti+>(lista3arg3constr); &ata un exemplu(
class GenericClass<)> $ +rivate ) genericAal!e;

+!blic GenericClass() genericAal!e) $ t*is genericAal!e = genericAal!e; 6 +!blic ) get() $ ret!rn genericAal!e;

6 +!blic void set() genericAal!e) $ t*is genericAal!e = genericAal!e; 6 6

-nde ) este parametrul tip ce va fi inlocuit in momentul in care clasa generica va fi apelata$ ca in exemplul urmator.
i%+ort java !til "; +!blic class Generic#2a%+le $ +!blic static void %ain(&tring'( args) $ GenericClass<&tring> gen4 = new GenericClass<&tring>(/<ello/); GenericClass<Integer> genB = new GenericClass<Integer>(D); GenericClass<>o!ble> genC = new GenericClass<>o!ble>(B C0); &yste% o!t +rintln(/gen4 genericAal!e este / @ gen4 get()); &yste% o!t +rintln(/genB genericAal!e este / @ genB get()); &yste% o!t +rintln(/genC genericAal!e este / @ genC get()); gen4 set(/Lorld/); &yste% o!t +rintln(/gen4 genericAal!e is / @ gen4 get());

66

!odul declara trei obiecte de tip GenericClass$ dar de versiuni diferite. Crearea metodelor generice si a constructorilor !onstructorul poate fi generic c)iar daca clasa nu este generica. !and declaram o metoda in interiorul clasei generice aceasta este capabila sa foloseasca parametrul tip al clasei. Putem apela o metoda generica in metoda %ain() fara a specifica argumentul tip. -rmatoarea secventa$ ba"ata pe exemplul anterior$ va genera o eroare la compilare(
gen4 set(genB get());

deoarece cele doua obiecte nu au aceeasi valoare a parametrului tip. Subclase generice !lasele generice pot forma ierar)ii de clase. !and o clasa generica mosteneste o alta clasa generica tipul parametru al superclasei trebuie sa fie declarat de subclasa. %ceasta trebuie reali"ata c)iar daca tipul nu este folosit in subclasa.
class &!bClasaGenerica<)-A> e2tends ClasaGenerica<)>

!and o clasa generica mosteneste o clasa negenerica nu trebuie sa specificam niciun argument.
class &!bClasaGenerica<)> e2tends Clasa1egenerica

&n continuare vom da un exemplu pentru a ilustra primul ca".

public class &!% $ public static void %ain(&tring'( args) $ GenericClass<&tring> gen4 = new GenericClass<&tring>(/<ello/); GenericClass<Integer> genB = new GenericClass<Integer>(D); GenericClass<>o!ble> genC = new GenericClass<>o!ble>(B C0); &yste% out +rintln(/gen4 genericAal!e este / @ gen4 get()); &yste% out +rintln(/genB genericAal!e este / @ genB get()); &yste% out +rintln(/genC genericAal!e este / @ genC get()); gen4 set(/Lorld/); &yste% out +rintln(/gen4 genericAal!e este / @ gen4 get()); // !r%atoarea linie ar ca!9a eroare la co%+ilare

// gen4 set(genB get()); Generic&!bclass<&tring- Integer> s!bGen = new Generic&!bclass(/Andy/- 05); boolean b4 = s!bGen instanceof GenericClass; boolean bB = s!bGen instanceof Generic&!bclass; // !r%atoarea linie ar ca!9a eroare la co%+ilare // boolean bC = s!bGen instanceo, GenericClass<&tring>; &yste% out +rintln(/este s!bGen instanta a GenericClassJ / @ b4); bB); GenericClass<Integer> genInt4 = null; GenericClass<&tring> genIntB = null; if (b4) $ // !r%atoarea linie ar ca!9a eroare la co%+ilare // GenericClass<Integer> genInt4 = (GenericClass<&tring>) s!bGen; // !r%atoarea linie 1G generea9a eroare la co%+ilare genIntB = (GenericClass<&tring>) s!bGen; 6 6 6 &yste% out +rintln(/este s!bGen instanta a Generic&!bclassJ / @

class GenericClass<)> $ private ) genericAal!e; public GenericClass() genericAal!e) $ this genericAal!e = genericAal!e; 6 public ) get() $ return genericAal!e; 6 public void set() genericAal!e) $ this genericAal!e = genericAal!e; 6

class Generic&!bclass<)- A> extends GenericClass<)> $ private A s!b)y+e; public Generic&!bclass() genericAal!e- A s!b)y+e) $ super(genericAal!e); this s!b)y+e = s!b)y+e; 6 public A get&!bty+e() $ return s!b)y+e; 6

/peratorul instanceo, ne permite sa determinam daca un obiect este o instanta a unei clase. %celasi lucru poate fi facut si pentru clasele generice.

&n codul anterior s!bGen este o instanta a lui GenericClass. .inia ce#l declara pe bC va genera o eroare la compilare. 'ipul GenericClass<&tring> nu exista la rulare pentru ca informatiile despre tipul obiectelor sunt indepartate la rulare printr# un proces numit type erasure. Putem converti o instanta a unei clase generice daca sursa si destinatia au argumente de tip identice sau compatibile. Tema: Sa se scrie o clasa utilitar generica$ fara a apela la colectii (liste$ set$ map$ etc $ cu metode statice$ ce ofera operatii pe un sir de obiecte generice. %poi$ folosind doar metodele acestei clase sa se afle maximul unui sir$ de obiecte concrete$ si po"itia pe care acesta se afla. &n final ultimele doua elemente ale sirului sa se inlocuiasca cu valoarea maximului$ respectiv a po"itiei acestuia.
public static <T, S extends T> S max(S[] coll, Comparator<? super T> comp); public static <T, S extends T> int binarySearch(S[] list, T key, Comparator<? super T> c); public static <T extends Comparable<? super T>> void sort(T[] list); @Sa e!arar"s public static <T, S extends T> void mo#i y$ear(S[] c, T%%% elements);&&pentr' mo#i icarea (alorilor 'ltimelor elemente #in sir

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