Cea mai simplă formă a unei declarații de clasă este următoarea:
class NumeClasa {
declaratii_de_membri
}
Observăm că declarația începe cu cuvântul-cheie class, urmat de numele clasei și de corpul clasei, cuprins între acolade.
Numele clasei este un identificator. Se obisnuiește ca numele clasei sa înceapă cu literă majusculă. Dacă numele este compus din mai multe cuvinte, fiecare din acestea începe cu majusculă.
Corpul clasei cuprinde declarații de
membri ai clasei respective. Acestea pot fi:
- declarații de câmpuri;
- declarații de constructori;
- declarații de metode.
Nu este obligatoriu ca într-o clasă să existe
toate aceste categorii de declarații. Pot exista, de exemplu, clase în
care apar numai declarații de metode. În principiu, pot exista și clase
care conțin numai câmpuri și nu conțin metode, deși astfel de situații
apar foarte rar în practică.
Câmpurile instanței se declară la fel ca variabilele locale ale metodelor,
numai că declarația respectivă nu apare în blocul unei metode, ci în
corpul clasei. De exemplu:
int m=172, n=2*m-4, r;
Aceste câmpuri pot avea valori diferite pentru
fiecare instanță a clasei respective. În consecință, câmpurile
instanței sunt plasate în zona de memorie rezervată instanței respective,
astfel că ele sunt distincte pentru fiecare instanță.
Câmpurile clasei se numesc și câmpuri statice.
Declararea unor astfel de câmpuri se face asemănător cu cea a câmpurilor
de instanță, dar declarația are în față, în acest caz, modificatorul static.De
exemplu:
static double u=3.65, v=2.87*u-3.1, x;
La inițializarea câmpurilor de instanță se pot
folosi atât valori ale câmpurilor statice, cât și ale altor câmpuri de
instanță. În schimb, la inițializarea câmpurilor statice se pot
folosi numai valori ale altor câmpuri statice.
Câmpurile statice (ale clasei) sunt
plasate în memorie în zona rezervată clasei căreia îi aparțin și
nu în cea rezervata instanțelor. În consecință, câmpurile clasei există
în memorie într-un singur exemplar, care este accesibil fiecărei
instanțe.
Valorile inițiale implicite ale
câmpurilor: dacă nu sunt inițializate
explicit, câmpurile statice și cele nestatice primesc valori
implicite astfel: Remarcăm, deci, că există o deosebire între crearea câmpurilor (variabilelor membre) și crearea variabilelor locale. La crearea câmpurilor, acestora li se atribuie implicit o valoare inițială, în timp ce la crearea variabilelor locale acestora trebuie sa li se atribuie valori în mod explicit. Dacă o variabilă locală apare într-o expresie fără să aibă o valoare atribuită anterior, compilatorul Java semnaleaza această situație ca o eroare de programare. |
Exemplu de clasă care nu conține constructori expliciți sau
metode:
Acest exemplu este dat în scop didactic, pentru a ilustra declararea, inițializarea și utilizarea câmpurilor. Crearea unei clase fără metode nu corespunde principiului de baza al programării orientate pe obiecte, conform căruia o clasă conține atât date, cât și metodele prin care acestea sunt tratate. În consecință, declararea unor clase fără metode se evită în practica programării orientate pe obiecte, chiar dacă o astfel de declarație este permisă. De altfel, chiar daca declarația de clasă nu conține constructori sau metode, ea are un constructor implicit (fără parametri) și moștenește metodele superclasei, în particular metodele clasei Object. |
În exemplul din fișierul TestClasa1.java se declară și se
utilizează o clasă care nu conține constructori si metode, ci numai
câmpuri de date. O astfel de clasă este folosită, deci, ca o structură
din limbajele neorientate pe obiecte (cum este struct în C sau record
în Pascal). În acest fișier sunt declarate două clase: clasa Proba1,
care este o simplă structură de date fără metode proprii, și clasa TestClasa1,
care conține metoda main si servește ca aplicație în care se testează
clasa Proba1.
Clasa Proba1 este declarată astfel:
/* Declararea clasei Proba1 Clasa contine numai campuri de date */ class Proba1 { |
În această clasă, s-au definit câmpurile
statice (ale clasei) m și n și câmpurile nestatice (de
instanță) a, b, c și d - toate de tip int.
S-au declarat, de asemenea, câmpurile c1 și c2 de tip char
și câmpurile s1, s2 și s3 care contin referințe la
instanțe ale clasei String. Unele din aceste câmpuri sunt
inițializate, altele au valori inițiale implicite. La inițializarea
câmpului de instanță b s-a folosit și valoarea câmpului static a.
Câmpurile c și d sunt inițializate implicit cu
valoarea 0.
Amintim o deosebire importantă între modul cum sunt plasate
în memorie valorile primitive și obiectele (instanțele claselor):
valorile primitive sunt plasate chiar în zona de memorie rezervată
variabilelor respective, în timp ce instanțele claselor sunt plasate în
memoria dinamică. În consecință: - valorile câmpurilor primitive statice m și n sunt plasate în memorie o singură dată, în spațiul rezervat clasei Proba1; - valorile câmpurilor primitive nestatice a, b, c, d, c1 și c2 sunt plasate în câmpurile corespunzătoare ale instanțelor clasei Proba1, deci acestea vor avea câte o valoare pentru fiecare instanță; - în campurile s1, s2 si s3 (care, în cazul nostru, sunt tot nestatice, deci se plaseaza în fiecare instanță), ca valori se pun numai referințe la instanțe ale clasei String. În consecință, șirurile "un șir" și "un șir extins" se vor creea în memoria dinamică, sub forma de obiecte ale clasei String, iar în câmpurile s1 și s2 ale fiecărei instanțe a clasei Proba1 se vor pune numai referințe la aceste șiruri. Câmpul s3 va fi inițializat cu referința null. |
Clasa Proba1 poate fi utilizată în alte clase
Java la fel ca o structură de date (înregistrare) "tradițională" cum ar
fi struct în limbajul C, sau record în limbajul Pascal.
Un exemplu de aplicație, în care se utilizează clasa Proba1, este clasa
TestClasa1 din fișierul TestClasa1.java,
pe care o reproducem în continuare.
/* Programul in care se utilizeaza clasa Proba1 ca o
structura obisnuita */ class TestClasa1 { |
La compilarea fișierului sursă TestClasa1.java, vor fi create două
fișiere bytecode, câte unul pentru fiecare clasă, numite în mod
corespunzător Proba1.class și TestClasa1.class. Pentru executarea
aplicației se va folosi comanda
java TestClasa1
Clasa Proba1 nu poate fi pusă în execuție în
acest mod, deoarece ea nu conține metoda main. Această clasă poate fi
folosită numai în cadrul altei clase.
Rezultatele afișate pe ecran la executarea
acestei aplicații sunt următoarele:
Campuri din p1: n=6 m=9 a=7 b=64
c=0 c1=@ c2= (int)p1.c2=0 Campuri din p2: n=6 m=9 a=7 b=64 c=0 s1=un sir s2=un sir extins s3=null Afisarea campurilor statice: m=9 n=6 Dupa modificarea valorilor campurilor a: Campuri din p1: n=6 m=9 a=12 b=64 c=0 Campuri din p2: n=6 m=9 a=-9 b=64 c=0 Dupa modificare: p1.m=-12 p2.m=-12 Proba1.m=-12 Dupa modificare: p1.n=-25 p2.n=-25 Proba1.n=-25 Dupa atribuire: p1.c=1234 p2.c=0 |
Urmărind aceste rezultate, putem constata că:
- câmpurile numerice neinițializate explicit
(inclusiv cele de tip char) sunt inițializate implicit la valoarea zero;
- valorile câmpurilor statice pot fi
utilizate calificând numele câmpului respectiv, atât cu numele unei
instanțe (de exemplu, p1.m), cât și calificandu-le cu numele clasei (de
exemplu, Proba1.m);
- valorile câmpurilor nestatice pot fi
utilizate numai calificând numele câmpului respectiv cu numele unei
instanțe (de exemplu, p2.a);
- dacă se atribuie o nouă valoare unui câmp
nestatic al unei instanțe, valorile câmpurilor cu același nume ale
celorlalte instanțe rămân nemodificate;
- dacă se atribuie o nouă valoare unui câmp
static, această modificare se constată în toate înstanțele, deoarece
câmpul respectiv este unic (există numai în cadrul clasei).