Scrigroup - Documente si articole

     

HomeDocumenteUploadResurseAlte limbi doc
AccessAdobe photoshopAlgoritmiAutocadBaze de dateCC sharp
CalculatoareCorel drawDot netExcelFox proFrontpageHardware
HtmlInternetJavaLinuxMatlabMs dosPascal
PhpPower pointRetele calculatoareSqlTutorialsWebdesignWindows
WordXml


Definirea de noi clase - Definirea unei clase in Java

java



+ Font mai mare | - Font mai mic



Definirea de noi clase

Definirea unei clase in Java



Definirea unei clase se face prin definirea variabilelor si functiilor clasei. In Java toate metodele trebuie definite (si nu doar declarate) in cadrul clasei. Ordinea in care sunt definiti membrii unei clase (date si functii) este indiferenta. Este posibil ca o metoda sa apeleze o alta metoda definita ulterior, in aceeasi clasa.

Datele clasei se declara in afara metodelor clasei si vor fi prezente in fiecare obiect al clasei. Ele sunt necesare mai multor metode si sunt de obicei putine. Variabilele clasei sunt accesibile tuturor functiilor clasei pentru citire sau modificare si sunt initializate de obicei in constructorul clasei.

Nu se vor defini ca variabile ale clasei acele variabile care sunt folosite numai in una sau doua functii ale clasei. Dimensiunea unui obiect este determinata mai ales de numarul si tipul variabilelor clasei si nu de numarul metodelor clasei. Atunci cand se creeaza multe obiecte dintr-o clasa, cum ar fi obiecte de tip nod de arbore sau obiecte ce corespund unor elemente din fisiere XML, este important ca dimensiunea lor sa fie mentinuta la minimum, dar in cazul unor clase cu un singur obiect (cum sunt clasele derivate din JFrame pentru fereastra aplicatiei) nu conteaza numarul variabilelor clasei.

Majoritatea claselor instantiabile grupeaza mai multe functii in jurul unor date comune. Ca exemplu vom schita o definitie posibila pentru o clasa ale carei obiecte sunt numere complexe (nu exista o astfel de clasa predefinita in bibliotecile JDK):

public class Complex

// scadere de numere complexe

public void sub ( Complex cpx)

}

Se observa ca metodele unei clase au putine argumente, iar aceste argumente nu se modifica, ceea ce este tipic pentru multe clase cu date: metodele clasei au ca efect modificarea datelor clasei, iar argumentele sunt de obicei date initiale necesare pentru operatiile cu variabilele clasei. Acesta este si un avantaj al programarii cu clase fata de programarea procedurala: functii cu argumente putine si care nu sunt modificate in functie.

Clasele de uz general se declara public pentru a fi accesibile din orice alt pachet.

Toate variabilele numerice ale unei clase sunt initializate implicit cu zerouri si toate variabile referinta sunt initializate cu null.

Variabilele de interes numai pentru anumite metode vor fi definite ca variabile locale in functii si nu ca variabile ale clasei. Exemplu de variabila locala unei metode:

public Complex conj ( )

Pentru utilizarea comoda a obiectelor clasei 'Complex' mai sunt necesare functii pentru initializarea datelor din aceste obiecte (numite 'constructori') si pentru afisarea datelor continute in aceste obiecte.

In Java clasele cu date nu contin metode de afisare pe ecran a datelor din obiectele clasei, dar contin o metoda cu numele "toString" care produce un sir de caractere ce reprezinta datele clasei si care poate fi scris pe ecran (cu metoda "System.out.println") sau introdus intr-un alt flux de date sau folosit de alte metode. Functia urmatoare (metoda a clasei 'Complex' ) trebuie inclusa in definitia clasei:

// conversie in sir, pentru afisare

public String toString ( )

Existenta metodei 'toString' ne permite sa afisam direct continutul unui obiect din clasa 'Complex' astfel:

Complex c = new Complex();

System.out.println (c); // scrie (0,0)

In plus, se poate afisa continutul unei colectii de obiecte 'Complex', pentru ca metoda 'toString' a colectiei apeleaza metoda 'toString' a obiectelor din colectie.

Redefinirea metodei 'equals' in clasa 'Complex' permite cautarea unui obiect dat intr-o colectie si alte operatii care necesita comparatia la egalitate. Exemplu:

public boolean equals (Object obj)

Functii constructor

Orice clasa instantiabila are cel putin un constructor public, definit implicit sau explicit si apelat de operatorul new la crearea de noi obiecte. Un constructor este o functie fara tip si care are obligatoriu numele clasei din care face parte. Constructorii nu sunt considerati metode, deoarece nu pot fi apelati explicit (prin nume).

Variabilele oricarei clase sunt initializate automat la crearea de obiecte (cu valori zero pentru variabile numerice si null pentru variabile de orice tip clasa). Aceste valori sunt preluate de fiecare obiect creat, daca nu se fac alte initializari prin constructori.

Pentru a permite configurarea obiectelor create se practica initializarea variabilelor clasei cu valori diferite pentru fiecare obiect in parte folosind unul sau mai multi constructori cu parametri. Exemplu:

public class Complex

. . . // metode ale clasei

}

Exemple de creare a unor obiecte de tipul "Complex" :

Complex c1 = new Complex (2,-3) ;

Complex c2= new Complex (0,1);

Daca nu se defineste nici un constructor atunci compilatorul genereaza automat un constructor implicit, fara argumente si fara efect asupra variabilelor clasei (dar care apeleaza constructorul superclasei din care este derivata clasa respectiva).

Este uzual sa existe mai multi constructori intr-o clasa, care difera prin argumente, dar au acelasi nume (un caz de supradefinire a unor functii). Exemplu:

public Complex ( Complex c)

Este posibila si supradefinirea unor metode ale claselor. De exemplu, putem defini doua metode de adunare la un complex, cu acelasi nume dar cu argumente diferite:

// adunare cu un alt complex

public void add ( Complex c)

// adunare cu un numar real

public void add ( double x)

In cazul cand argumentele unui constructor sunt referinte la alte obiecte (si nu valori primitive) se retin de obicei aceste referinte in obiectul creat si nu se creeaza alte obiecte. Exemplu:

class Pair

. // metode ale clasei

}

Uneori metodele clasei chiar trebuie sa modifice obiectele ale caror adrese le primeste, iar alteori nu exista posibilitatea modificarii acestor obiecte (din clase "read-only").

In cazul cand variabilele clasei sunt vectori intrinseci sau clase colectie in constructor se aloca memorie pentru vectori sau colectii. Exemplu:

public class IntVector

. . . // metode ale clasei

}

Variabilele unei clase pot fi initializate la declararea lor, cu efect pentru toate obiectele clasei. Acest fel de initializare se practica pentru variabile membru de tip clasa si pentru clase cu un singur obiect. Exemplu de initializare a unei variabile la declarare:

class TextFrame extends JFrame

. . . // alte metode

}

Intr-o aplicatie se va crea un singur obiect de tip 'TextFrame', iar obiectul de la adresa 't' va avea intotdeauna marimea 10. Instructiunea din constructor se va executa o singura data, dar trebuie sa fie inclusa intr-o functie. Crearea obiectului camp text JTextField nu se face printr-o instructiune ci printr-o declaratie cu initializare.

Initializari ale variabilelor clasei se mai pot face intr-un bloc cuprins intre acolade (inclus de compilator in orice constructor), intr-un bloc static de initializare sau intr-o metoda statica private.

In Java nu sunt permise argumente formale cu valori implicite, dar un constructor cu mai putine argumente poate apela un constructor cu mai multe argumente, dintre care unele au valori implicite.

Un constructor nu poate fi apelat explicit, ca si o metoda, iar atunci cand este necesar acest apel (din aceeasi clasa) se foloseste cuvantul cheie this ca nume de functie. Exemple:

// constructor cu un parametru din clasa Complex

public Complex (double re) // apel constructor cu doua argumente

// constructor fara parametri din clasa Complex

public Complex () // apel constructor cu un argument

Cuvantul cheie 'this'

Metodele nestatice dintr-o clasa actioneaza asupra unor obiecte din acea clasa. Atunci cand se apeleaza o metoda pentru un anumit obiect, metoda primeste ca argument implicit o referinta la obiectul respectiv. Altfel spus, instructiunile urmatoare :

int n = a.length(); // lungimea sirului a

String b = a.substring (k); // extrage subsir din pozitia k din sirul a

corespund instructiunilor urmatoare din limbajul C:

int n = length(a); // lungimea sirului a

String b = substring (a,k); // extrage subsir din pozitia k din sirul a

Acest argument implicit poate fi folosit in interiorul unei metode nestatice prin intermediul variabilei predefinite this. Cuvantul cheie this este o variabila referinta care desemneaza in Java adresa obiectului curent ('acest obiect').

Definitia metodei 'length' ar putea fi rescrisa folosind variabila this astfel:

public int length (this)

In mod normal nu trebuie sa folosim variabila this pentru referire la datele sau la metodele unui obiect, dar exista situatii cand folosirea lui this este necesara.

Un prim caz de folosire curenta a variabilei this este la definirea unui constructor cu argumente formale avand aceleasi nume cu variabile ale clasei. Exemplu:

public Complex ( float re, float im)

Astfel de situatii pot fi evitate prin alegerea unor nume de argumente diferite de numele variabilelor clasei, dar clasele JDK folosesc aceleasi nume (si variabila this ) pentru ca argumentele unui constructor contin valori initiale pentru variabilele clasei.

Un alt caz de folosire a variabilei this este in instructiunea return, pentru metodele care modifica datele unui obiect si au ca rezultat obiectul modificat. Exemplu:

public final class StringBuffer

// alte metode ale clasei StringBuffer

}

Un caz particular este metoda 'toString' din clasa 'String':

public String toString ()

Uneori un obiect isi trimite adresa sa metodei apelate (metoda statica sau dintr-un alt obiect). Exemple:

// un vector isi transmite adresa sa metodei statice de sortare

class SortedVec extends Vector

}

Variabila this nu poate fi folosita in metode statice.

Atribute ale membrilor claselor

Membrii unei clase, variabile si metode, au in Java mai multe atribute: tipul variabilei sau metodei ( tip primitiv sau tip clasa ), un atribut de accesibilitate (public, protected, private) plus atributele static, final, abstract (numai pentru metode).

Cu exceptia tipului, fiecare din aceste atribute are o valoare implicita, folosita atunci cand nu se declara explicit o alta valoare. Cuvintele cheie folosite pentru modificarea atributelor implicite se numesc 'modificatori'. De exemplu orice membru este nestatic si nefinal atunci cand nu se folosesc modificatorii static sau final.

O variabila statica a clasei declarata final este de fapt o constanta, nemodificabila prin operatii ulterioare primei initializari. Exemple de constante din clasa Byte:

public class Byte

Se vede din exemplul anterior ca o variabila statica finala poate fi initializata si cu rezultatul unei functii, pentru ca initializarea se face la incarcarea clasei.

Metodele unei clase instantiabile sunt de obicei nestatice, dar pot exista si cateva metode statice in fiecare clasa cu date. Exemplu din clasa String:

public static String valueOf(Object obj)

O metoda statica poate fi apelata de o metoda nestatica. Exemplu:

public String toString()

O metoda statica (inclusiv functia main) nu poate apela o metoda nestatica, pentru ca folosirea unei metode nesatice este conditionata de existenta unui obiect, dar metoda statica se poate folosi si in absenta unor obiecte. O metoda statica poate apela un constructor. Exemplu:

public static Integer valueOf (String s) throws NumberFormatException

Parte din definitia unei metode este si clauza throws, care specifica ce fel de exceptii se pot produce in metoda respectiva si care permite compilatorului sa verifice daca exceptiile produse sunt sau nu tratate acolo unde se apeleaza metoda. Exemplu de metoda din clasa Integer, pentru conversia unui sir de caractere intr-un intreg :

public static int parseInt (String s) throws NumberFormatException

Anumite situatii speciale aparute in executia unei metode sunt uneori raportate prin rezultatul functiei (boolean) si nu prin exceptii. De exemplu, anumite functii de citire a unui octet dintr-un fisier au rezultat negativ la sfarsit de fisier, iar functia de citire a unei linii (intr-un obiect String) are rezultat null la sfarsit de fisier.

Uneori este posibila anticiparea si prevenirea unor exceptii. Exemplul urmator arata cum se poate evita aparitia unei exceptii de iesire din limitele unui vector intrinsec, din cauza utilizarii gresite a unui program Java:

// program cu doua argumente in linia de comanda

public static void main ( String arg[ ])

. . . // prelucrare argumente primite

}

O metoda declarata final nu mai poate fi redefinita intr-o subclasa si ar putea fi implementata mai eficient de catre compilator.

O metoda abstracta este o metoda cu atributul abstract, declarata dar nedefinita in clasa unde apare pentru prima data. O clasa care contine cel putin o metoda abstracta este o clasa abstracta si nu poate fi instantiata, deci nu se pot crea obiecte pentru aceasta clasa (dar se pot defini variabile de un tip clasa abstracta).

Metode declarate dar nedefinite in Java sunt si metodele 'native' (cu atributul native), care se implementeaza intr-un alt limbaj decat Java (de obicei limbajul C). Definitia lor depinde de particularitatile sistemului de calcul pe care se implementeaza metodele. Exemplu de metoda nativa:

public static native void arraycopy (Object s, int si, Object d, int di, int length);

Incapsularea datelor in clase

De obicei datele unei clase nu sunt direct accesibile utilizatorilor clasei, deci nu sunt accesibile functiilor din alte clase. Pe de o parte utilizatorii nu sunt interesati de aceste date (de exemplu, cel care foloseste o stiva nu are nevoie sa "vada" vectorul stiva si alte detalii), iar pe de alta parte este mai sigur ca aceste date sa fie modificate numai de metodele clasei si nu de catre orice utilizator.

O clasa expune utilizatorilor sai o interfata publica, care consta din totalitatea metodelor publice (accesibile) ale clasei si care arata ce se poate face cu obiecte ale clasei respective. Documentatia unei clase prezinta numai interfata sa publica, adica constructorii publici, metodele publice (tip, nume, argumente) si variabilele public accesibile. Este posibila modificarea implementarii unei clase, cu mentinerea interfetei sale. De exemplu, putem folosi o stiva realizata ca lista inlantuita in locul unei stive vector, fara ca programele ce folosesc stiva sa necesite vreo modificare.

Atributul de accesibilitate se refera la drepturile unei clase asupra membrilor unei alte clase, si este legat de ceea ce se numeste 'incapsulare' sau 'ascunderea datelor'. Toate obiectele unei clase au aceleasi drepturi, stabilite la definitia clasei.

Metodele unei clase pot folosi variabilele clasei, indiferent de atributul de accesibilitate al acestor variabile (private, protected, public). Metodele unei clase se pot apela unele pe altele, indiferent de ordinea definirii lor si de atributul de accesibilitate.

Atributul public se foloseste pentru functiile si/sau variabilele clasei ce urmeaza a fi folosite din alte clase. In general, metodele si constructorii unei clase se declara public. Variabilele public accesibile se mai numesc si proprietati ale obiectelor.

Datele unei clase au in general atributul private sau protected, iar accesul la aceste date este permis numai prin intermediul metodelor, publice, ale clasei respective.

Exista si cazuri, mai rare, in care nu se respecta principiul incapsularii iar variabilele unei clase sunt public accesibile. Este vorba de clase cu mai multe variabile, folosite relativ frecvent in alte clase si pentru care accesul prin intermediul metodelor ar fi incomod si ineficient. Exemplu din pachetul "java.awt":

public class Rectangle

// alte metode

}

Un alt exemplu este clasa StreamTokenizer din pachetul "java.io". Un obiect StreamTokenizer este un mic analizor lexical, care recunoaste tipul urmatorului simbol extras dintr-un fisier (flux de date): numar, cuvant sau caracter special. Tipul urmatorului simbol este rezultatul unei metode, dar valoarea numarului sau sirului cuvant se afla in variabile publice ale clasei. Exemplu:

public static void main (String arg[]) throws Exception

}

Variabilele "sval" (de tip String) si "nval" (de tip double) sunt variabile publice, iar TT_EOF, TT_WORD si TT_NUMBER sunt constante (variabile publice statice si finale) din clasa StreamTokenizer. O solutie alternativa ar fi fost obtinerea valorii cu o metoda publica avand un rezultat de tipul generic Object, dar utilizarea acestei valori ar fi necesitat o conversie la tipul indicat de metoda "nextToken".

Variabilele cu atributul protected dintr-o clasa sunt accesibile pentru toate clasele derivate direct din A (indiferent de pachetul unde sunt definite) si pentru clasele din acelasi pachet cu ea.

Daca nu se specifica explicit modul de acces la un membru al unei clase A atunci se considera implicit ca el este accesibil pentru toate clasele definite in acelasi pachet cu A, numite uneori clase "prietene". De exemplu, clasele VectorEnumerator si Vector sunt definite (in Java 1.0) in acelasi pachet si in acelasi fisier sursa, iar variabile cu atributul protected din clasa Vector sunt folosite direct in clasa VectorEnumerator (in Java 1.2 clasa enumerator este inclusa in clasa vector).

In continuare vom schita definitia unei clase pentru o lista inlantuita de numere intregi. Mai intai trebuie definita o clasa pentru un nod de lista, o clasa care poate sa nu aiba nici o metoda si eventual nici constructor explicit:

class Node // constructor

}

Metodele clasei lista trebuie sa aiba acces direct la variabilele clasei "Node", ceea ce se poate realiza in doua moduri:

- Clasele "Node" si "MyList" se afla in acelasi pachet.

- Clasa "Node" este interioara clasei "MyList".

In ambele cazuri variabilele clasei "Node" pot sa nu aiba nici un atribut explicit de accesibilitate. Clasa "MyList" contine o variabila de tip "Node" (adresa primului element din lista), care poate fi "private" sau "protected", daca anticipam eventuale subclase derivate.

public class MyList

// adaugare la sfirsit de lista

public void add (int v)

// sir ptr. continut lista

public String toString ()

return aux; // sirul cu toate valorile din lista

}

}

Pentru metoda "contains" vom defini o functie auxiliara recursiva, cu un argument suplimentar, care se modifica de la un apel la altul (adresa primului nod din sublista in care se cauta):

// cautare in lista (metoda a clasei MyList)

public boolean contains (int x)

// fct recursiva de cautare (din clasa MyList)

private boolean find (Node crt, int x)

Functia "find" putea fi si statica ( private static boolean find ).

Structura unei clase Java

O clasa care poate genera obiecte contine in mod normal si date, deci variabile ale clasei, definite in afara metodelor clasei (de obicei inaintea functiilor).

Majoritatea claselor instantiabile au unul sau mai multi constructori publici folositi pentru initializarea obiectelor si apelati de operatorul new.

Metodele unei clase pot fi clasificate in cateva grupe:

- Metode care permit citirea datelor clasei ( metode accesor).

- Metode care permit modificarea datelor clasei ( si care lipsesc din anumite clase ).

- Metode pentru operatii specifice clasei respective.

- Metode mostenite de la clasa Object si redefinite, pentru operatii generale, aplicabile oricarui obiect Java ( "equals", "toString", "hashCode").

Conform unor cerinte mai noi ale standardului Java Beans, metodele de acces la variabile private au un nume care incepe cu 'get' si continua cu numele variabilei, iar metodele de modificare a variabilelor au un nume care incepe cu 'set'. Exemplu:

public class Complex // extrage parte reale

public float getImag ( ) // extrage parte imaginara

// metode de modificare a datelor

public void setReal (float x) // modifica parte reala

public void setImag (float y) // modifica parte imaginara

// complex conjugat

public Complex conj ()

// alte operatii cu obiecte de tip Complex

. . .

// metode din "Object" redefinite

public boolean equals (Object obj)

public String toString ()

}

Componentele JavaBeans sunt clase care se pot instantia de catre un operator prin intermediul unui mediu vizual de dezvoltare (tipic sunt componente de interfata grafica: butoane, casute cu text, s.a.), dupa care se pot modifica proprietatile lor (tot interactiv, in faza de proiectare a interfetei grafice). De aceea clasele JavaBeans au si un constructor fara argumente si, obligatoriu, metode pentru citirea si modificarea proprietatilor (care sunt variabile private ale clasei).

Clasele cu date care se instantiaza exclusiv prin program (prin operatorul new) vor avea constructori cu argumente, pentru ca este mai comod sa stabilim proprietatile la construirea obiectului.

Clasa String contine un vector de caractere si dimensiunea sa, mai multi constructori si diverse functii care realizeaza operatii uzuale asupra acestui vector: cautarea unui caracter dat in vector, extragerea unui subsir din intregul sir, compararea cu un alt sir etc. Exemplu:

public class String

// metodele clasei

public int length ()

public String substring (int start, int end)

public String substring (int pos)

// alte metode

}

A se observa existenta unor metode cu acelasi nume dar cu argumente diferite si modul in care o metoda (nestatica) apeleaza o alta metoda nestatica din clasa: nu se mai specifica obiectul pentru care se apeleaza metoda "substring" cu doi parametri, deoarece este acelasi cu obiectul pentru care s-a apelat metoda "substring" cu un singur parametru (obiectul this = chiar acest obiect).

O clasa mai poate contine constante si chiar alte clase incluse.

In limbajul C o declaratie de structura este o definitie de tip care nu aloca memorie si de aceea nu este posibila initializarea membrilor structurii. In Java o definitie de clasa creeaza anumite structuri de date si aloca memorie, ceea ce justifica afirmatia ca o clasa este un fel de sablon pentru crearea de obiecte de tipul respectiv. Definitia unei clase Java nu trebuie terminata cu ';' ca in C++.

Metode care pot genera exceptii

In antetul unor metode trebuie sa apara clauza throws, daca in aceste metode pot apare exceptii, a caror tratare este verificata de compilator. Intr-o metoda poate apare o exceptie fie datorita unei instructiuni throw, fie pentru ca se apeleaza o metoda in care pot apare exceptii.

La executia unei metode sau unui constructor este posibil sa apara o situatie de exceptie, iar metoda trebuie sa anunte mai departe aceasta exceptie. Semnalarea unei exceptii program inseamna in Java crearea unui obiect de un anumit tip clasa (derivat din clasa Exception) si transmiterea lui in afara functiei, catre sistemul care asista executia ('Runtime system'). Exemplu de metoda care verifica daca parametrul primit este eronat, caz in care produce o exceptie:

public char charAt (int index)

Instructiunea throw se foloseste pentru generarea unei exceptii intr-o metoda si specifica un obiect "exceptie"(de obicei un obiect creat ad-hoc chiar in instructiune). Alegerea acestui cuvant ('to throw'= a arunca) se explica prin aceea ca la detectarea unei exceptii nu se apeleaza direct o anumita functie (selectata prin nume); functia care va trata exceptia (numita 'exception handler') este selectata dupa tipul obiectului exceptie 'aruncat' unui grup de functii.

Metoda 'charAt' arunca o exceptie care nu trebuie declarata.

O metoda in care se poate produce o exceptie si care arunca mai departe exceptia trebuie sa contina in definitia ei clauza throws. Cuvantul cheie throws apare in antetul unei metode, dupa lista de argumente si este urmat de numele unui tip exceptie (nume de clasa) sau de numele mai multor tipuri exceptie. In Java se considera ca erorile semnalate de o metoda fac parte din antetul metodei pentru a permite compilatorului sa verifice daca exceptia produsa este ulterior tratata si sa oblige programatorii la tratarea anumitor exceptii. Exemplu de exceptie generata de un constructor:

public static FileReader fopen ( String filename) throws IOException

Orice functie (metoda) care apeleaza metoda "fopen" de mai sus trebuie fie sa arunce mai departe exceptia (prin clauza throws), fie sa o trateze (prin try-catch):

public static void fileCopy ( String src, String dst) throws IOException

catch (IOException ex) // daca fisier negasit

}

Pentru erori uzuale sunt predefinite o serie de tipuri exceptie, dar utilizatorii pot sa-si defineasca propriile tipuri exceptie, sub forma unor noi clase (derivate fie din clasa Exception fie din clasa RuntimeException).

Pentru erorile care nu permit continuarea programului vom prefera exceptiile derivate din clasa RuntimeException sau din clasa Error, care nu obliga programatorul la o anumita actiune ('prindere' sau aruncare mai departe). Exista chiar parerea ca toate exceptiile ar trebui sa fie de acest fel, pentru simplificarea codului (prin eliminarea clauzei throws din antetul metodelor) si pentru a evita tratarea lor superficiala (prin interzicerea oricarui mesaj la aparitia exceptiei).

Clase si obiecte Java in faza de executie

Pentru fiecare clasa incarcata in masina virtuala Java este creat automat cate un obiect de tip Class, cu informatii despre clasa asociata (metadate). Obiecte Class sunt create automat si pentru interfete, clase abstracte si vectori intrinseci Java.

Prin "reflectie" ("reflection") se intelege obtinerea de informatii despre o clasa sau despre un obiect in faza de executie (este "reflectata" starea masinii virtuale). In plus, se pot crea si modifica dinamic obiecte in faza de executie.

Reflectia este asigurata in principal de clasa numita Class, dar si de alte clase din pachetul "java.lang.reflect": Constructor, Method, Field, s.a.

O variabila de tip Class contine o referinta la un obiect descriptor de clasa; ea poate fi initializata in mai multe feluri:

- Folosind cuvantul cheie class (literalul class) ca si cum ar fi un membru public si static al clasei sau tipului primitiv :

Class cF = Float.class, cS = Stiva.class, // clase predefinite sau proprii

cf = float.class, cv =void.class, // tipuri primitive

cN= Number.class, cI=Iterator.class ; // clase abstracte si interfete

- Folosind metoda statica "forName" cu argument nume de clasa (ca sir de caractere):

Class cF = Class.forName("java.util.Float"), cf = Class.forName ("float");

- Folosind metoda "getClass" pentru o variabila de orice tip clasa (metoda "getClass" este mostenita de la clasa Object, deci exista in orice clasa):

Float f = new Float (3.14); Class cF = f.getClass();

Clasa Class contine metode care au ca rezultat numele clasei, tipul clasei (clasa sau interfata sau vector), tipul superclasei, clasa externa, interfete implementate, tipul obiectelor declarate in clasa, numele campurilor (variabilelor clasei), numele metodelor clasei, formele functiilor constructor s.a.

Metoda "getName" are ca rezultat un sir ce reprezinta numele clasei al carui tip este continut intr-un obiect Class. Exemplul urmator arata cum se poate afisa tipul real al unui obiect primit ca argument de tipul generic Object:

void printClassName (Object obj)

Crearea de obiecte de un tip aflat in cursul executiei dar necunoscut la compilare (cu conditia ca tipul respectiv sa fi fost definit printr-o clasa, iar fisierul "class" sa fie accesibil la executie) se poate face simplu daca in clasa exista numai un constructor fara argumente . Exemplu:

public static Object getInstance (String clsname) throws Exception

Deoarece putem obtine toti constructorii unei clase, cunoscand tipul argumentelor, se pot "fabrica" obiecte si apeland constructori cu argumente. Exemplu:

public static Object newObject (Constructor constructor, Object [ ] args) catch (Exception e)

return obj;

}

// utilizare

Float x;

Class cls = Float.class;

Class[] argsCls = new Class[ ] ; // tip argumente constructor

Constructor constr = cls.getConstructor(argsCls); // obtinere constructor

Object[] args = new Object[ ] ; // argument efectiv ptr instantiere

x =(Float) newObject (constr,args);

Prin reflectie un asamblor de componente dintr-un mediu vizual poate sa determine proprietatile si metodele proprii unor obiecte, sa modifice proprietatile acestor obiecte si sa genereze apeluri de metode intre obiecte.

In rezumat, reflectia permite operatii cu clase si cu obiecte necunoscute la scrierea programului, dar care pot fi determinate dinamic, in cursul executiei.

De observat ca tipul unui obiect nu este neaparat acelasi cu tipul variabilei prin care se fac referiri la obiect; tipul variabilei poate fi o interfata, o clasa abstracta sau neabstracta din care este derivat tipul obiectului, deci tipul variabilei poate fi mai general decat tipul obiectului. De exemplu, rezultatul unei metode de extragere dintr-un vector (elementAt) este de tip Object, dar tipul real al obiectului poate fi orice tip clasa. Pentru apelarea metodelor specifice clasei respective se face o conversie prin operatorul "cast" la tipul cunoscut. Exemplu:

Vector v = new Vector();

v.add (new Integer(1)); // adauga la v un obiect de tip Integer

. . .

int x = (Integer)v.elementAt(0).intValue(); // x= 1

Utilizarea metodei "intValue" fara conversie prealabila este semnalata ca eroare la compilare, deoarece metoda nu exista in clasa Object, iar compilatorul verifica daca metodele (nestatice) apelate exista in clasa de tipul careia este variabila.

Daca se apeleaza metode polimorfice pentru obiecte de tip necunoscut, atunci se va apela automat varianta definita in clasa respectiva, chiar daca programatorul (si nici compilatorul) nu stie care este tipul exact al obiectului. Exemplu:

String s = v.elementAt(i).toString(); // se apeleaza Integer.toString()

if ( v.elementAt(i).equals(obj)) // se apeleaza Integer.equals()

De aceea determinarea tipului unui obiect la executie, folosind obiectul Class asociat, este rareori necesara in programele obisnuite.




Politica de confidentialitate | Termeni si conditii de utilizare



DISTRIBUIE DOCUMENTUL

Comentarii


Vizualizari: 1310
Importanta: rank

Comenteaza documentul:

Te rugam sa te autentifici sau sa iti faci cont pentru a putea comenta

Creaza cont nou

Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved