Definirea unei clase
Clasele sunt elemente fundamentale ale oricarei aplicatii Java. Ele reprezinta structuri logice care definesc comportamentul si starea obiectelor.
O clasa este definita pentru a descrie un nou tip de date. Dupa definirea clasei, aceasta poate fi utilizata pentru a crea obiecte de tipul respectiv. Deci, o clasa reprezinta un sablon pentru un obiect, iar un obiect reprezinta o instanta a unei clase.
Forma generala pentru declararea unei clase este urmatoarea:
[modificatori_clasa] class nume_clasa [extends super_clasa][implements lista_interfete] { // corp_clasa }
Dupa cum se poate observa, sintaxa de mai sus cuprinde o serie de termeni optionali:
• modificatori_clasa: definesc aria de vizibilitate si drepturile de acces sau anumite caracteristici ale clasei; pentru o clasa pot fi utilizati urmatorii modificatori: public, abstract, final;
• extends super_clasa: precizeaza clasa de baza (superclasa) pentru clasa definita; Java permite doar mostenirea simpla, ceea ce inseamna ca o clasa poate avea doar un singur parinte;
• implements lista_interfete: listeaza interfetele care sunt implementate de noua clasa.
Corpul unei clase poate contine doua tipuri de elemente: date membre (atribute) si functii membre (metode). Atributele si metodele definite intr-o clasa reprezinta membrii clasei.
Utilizarea modificatorilor
Modificatorii de vizibilitate si drepturi de acces sunt cuvinte cheie care precizeaza aria de vizibilitate si drepturile de acces ale clientilor la membrii unei clase. Clienti pot fi metodele sau clasele care acceseaza din exterior un membru.
Modificatorii au o arie larga de utilizare care poate cuprinde definitii de clase, atribute sau metode. Urmatorii termeni pot fi utilizati ca si modificatori de vizibilitate: public, protected si private.
Daca nu este precizat un modificator de vizibilitate pentru un membru, atunci acesta este accesibil la nivelul pachetului din care face parte clasa in care acesta se gaseste.
Modificatorul public utilizat in cadrul declaratiei unei clase face ca aceasta sa fie vizibila de oriunde. Daca modificatorul public precede declararea unei variabile sau a unei metode, acestea sunt vizibile oriunde este vizibila clasa.
public tip variabilaPublica;
La nivelul membrilor unei clase poate fi utilizat modificatorul private, care stabileste vizibilitatea membrilor numai in interiorul clasei in care sunt declarati.
private tip variabilaPrivata;
Modificatorul protected este utilizat in declararea variabilelor sau a metodelor. Membrii declarati cu protected sunt accesibili in cadrul clasei, subclaselor sau pachetului din care face parte clasa.
protected tip variabilaProtejata;
Pentru declararea variabilelor de clasa (atribute statice) se poate utiliza un modificator special, static. Variabilele declarate cu static sunt partajate de catre obiectele clasei. Daca modificatorul static apare in declaratia unei metode, vorbim despre metode de clasa, metode care pot fi apelate si fara a instantia obiecte ale clasei.
public static tip valoarePartajata;
Un alt modificator care este utilizat in cazul membrilor unei clase este final. Variabilele declarate cu final au o valoare constanta, care nu poate fi modificata prin program. Atunci cand o metoda este declarata cu modificatorul final nici o alta clasa nu va putea supradefini metoda, adica nu va putea fi redefinita intr-o subclasa.
public static final int MAX = 256;
O clasa care contine metode neimplementate poarta numele de clasa abstracta si se declara utilizand modificatorul abstract. Metodele abstracte (neimplementate) continute de o clasa abstracta se declara folosind modificatorul abstract.
public abstract double aria();
Pe baza modificatorilor de vizibilitate pot fi definite patru niveluri de acces:
• public;
• private;
• protected;
• package (implicit).
Declararea variabilelor si implementarea metodelor
In limbajul Java orice clasa contine doua tipuri de elemente (membri): atribute si metode.
Atributele reprezinta aspecte individuale care diferentiaza un obiect de altul si determina modul de afisare, starea sau calitatile unui obiect. Atributele din interiorul unei clase pot fi statice si non-statice.
Atributele statice sunt asociate clasei si sunt partajate de toate obiectele acesteia. Aceste atribute pot fi utilizate chiar si in situatia in care nu se instantiaza obiecte ale clasei. Se mai numesc si variabile de clasa deoarece aceste atribute apartin clasei si nu unui obiect anume. Pentru a declara o variabila de clasa trebuie utilizat modificatorul static.
Atributele non-statice sau variabilele instanta reprezinta cel de-al doilea tip de atribute dintr-o clasa. Fiecare instanta a unei clase va detine o copie a variabilelor instanta care sunt definite in respectiva clasa. De asemenea, fiecare obiect va avea propriile valori pentru fiecare atribut non-static.
class Cerc { | |
// variabila clasa | |
static final double PI = 3.14; | |
// variabile instanta | |
double x; | |
double y; | |
double raza; | |
} |
Dupa cum se poate observa, declararea unei variabile are urmatoarea forma:
[modificatori] tip_variabila nume_variabila [ = valoare_initializare];
In functie de tipul modificatorilor prezenti in declaratia unui atribut se poate preciza nivelul de acces la acel atribut, tipul atributului (instanta, clasa) sau se poate stabili daca atributul este o constanta (variabila finala).
Metodele unei clase definesc comportamentul clasei respective. In mod similar atributelor, intr-o clasa pot fi definite doua tipuri de metode: statice sau metode clasa si non-statice sau metode instanta.
Metodele statice se declara utilizand modificatorul static si pot fi apelate chiar si in cazul in care nu au fost instantiate obiecte ale clasei. Deoarece acest tip de metode pot fi executate si in absenta obiectelor, ele nu vor fi referite de variabile instanta. Metoda main() trebuie declarata folosind modificatorul static.
class Cerc { | |
static final double PI = 3.14; | |
static int count = 0; | |
double x; | |
double y; | |
double raza; | |
// metoda non-statica | |
public double aria() { | |
return PI * raza * raza; | |
} | |
// metoda statica | |
static int nrObiecte() { | |
return count; | |
} | |
} |
Declararea unei metode se face respectand urmatoarea sintaxa generala:
[modificatori] tip_metoda nume_metoda( [lista parametri] ) [throws tip_exceptie1, ... ] { // corp metoda }
Clauza throws este utilizata pentru declararea exceptiilor care pot rezulta in urma executiei unei metode. Exceptiile reprezinta conditii care apar la rulare si necesita oprirea programului, fiind tratate prin obiecte ale casei java.lang.Throwable.
Polimorfismul
Unul din principiile de baza in programarea orientata pe obiecte este polimorfismul. Polimorfismul specifica situatia in care un nume se refera la doua metode diferite. Limbajul Java permite definirea a doua tipuri de polimorfism:
• tipul de supraincarcare;
• tipul de supradefinire.
Polimorfismul de supraincarcare apare la definirea de metode cu acelasi nume in cadrul unei clase. Diferenta intre metode se face prin numarul de parametri sau tipurile diferite ale acestor parametri. Nu poate fi realizata supraincarcarea prin utilizarea de tipuri returnate diferite pentru metode.
class Carte { | |
String titlu; | |
String autor; | |
Carte() { | |
titlu = " "; | |
autor = " "; | |
} | |
Carte(String titlu, String autor) { | |
this.titlu = titlu; | |
this.autor = autor; | |
} | |
void fisaCarte() { | |
System.out.println("Titlu: " + titlu); | |
System.out.println("Autor: " + autor); | |
} | |
void fisaCarte(int id) { | |
System.out.println("Id: " + id); | |
System.out.println("Titlu: " + titlu); | |
System.out.println("Autor: " + autor); | |
} | |
public static void main(String[] args) { | |
Carte c1 = new Carte("Morometii", "Marin Preda"); | |
Carte c2 = new Carte("Fratii Jderi", "Mihail Sadoveanu"); | |
c1.fisaCarte(); | |
c1.fisaCarte(1); | |
c2.fisaCarte(2); | |
} | |
} |
Cuvantul cheie this returneaza o referinta catre obiectul curent. In interiorul metodei constructor this este utilizat pentru a face diferenta intre variabilele de instanta si variabilele locale, deoarece acestea au aceeasi denumire.
this.titlu = titlu;
Polimorfismul de supradefinire apare in momentul in care metoda unei clase are acelasi nume si aceeasi semnatura cu o metoda din clasa de baza. Semnatura unei metode este data de numarul parametrilor, tipul si ordinea acestora. Spunem ca metoda din clasa derivata supradefineste metoda din clasa de baza, daca numele si semnaturile metodelor coincid.
package ro.virtualcampus.person; | |
public class Persoana { | |
private String nume; | |
private int varsta; | |
private double inaltime; | |
public Persoana() { | |
this("Necunoscut", 0, 0.0); | |
} | |
public Persoana(String nume, int varsta, double inaltime) { | |
this.nume = nume; | |
this.varsta = varsta; | |
this.inaltime = inaltime; | |
} | |
public Persoana(String nume) { | |
this(nume, 0, 0.0); | |
} | |
public String getNume() { | |
return this.nume; | |
} | |
public int getVarsta() { | |
return varsta; | |
} | |
public double getInaltime() { | |
return inaltime; | |
} | |
public void sePrezinta() { | |
System.out.printf("Numele meu este %s.%n", this.nume); | |
} | |
} |
Clasa Student introduce prin intermediul polimorfismului metoda sePrezinta(). Aceasta suprascrie metoda din superclasa Persoana care are acelasi nume si aceeasi semnatura.
package ro.virtualcampus.person; | |
public class Student extends Persoana { | |
private double medie; | |
private String facultate; | |
public Student() { | |
super(); | |
this.medie = 0.0; | |
this.facultate = null; | |
} | |
public Student(String nume, int varsta, double inaltime, double medie, String facultate) { | |
super(nume, varsta, inaltime); | |
this.medie = medie; | |
this.facultate = facultate; | |
} | |
public double getMedie() { | |
return medie; | |
} | |
public String getFacultate() { | |
return facultate; | |
} | |
@Override | |
public void sePrezinta() { | |
super.sePrezinta(); | |
System.out.printf("Sunt student la facultatea %s.%n", getFacultate()); | |
} | |
public void sePrezinta(String salut) { | |
System.out.printf("%s! ", salut); | |
this.sePrezinta(); | |
} | |
} |
Cuvantul cheie super permite accesarea atributelor si metodelor superclasei. Astfel, in constructorul din subclasa se poate accesa constructorul din clasa de baza.
package ro.virtualcampus.person; | |
class Aplicatie { | |
public static void main(String[] args) { | |
Persoana vp = new Persoana("Virgil Popescu", 45, 1.68); | |
Student db = new Student("Doria Banciu", 35, 1.67, 7.80, "ETTI"); | |
vp.sePrezinta(); | |
db.sePrezinta("Buna zua"); | |
} | |
} |
Numele meu este Virgil Popescu. Buna ziua! Numele meu este Doria Banciu. Sunt student la facultatea ETTI.
Instantierea obiectelor unei clase
Definirea unei clase presupune crearea unui nou tip de date. Acesta poate fi utilizat pentru declararea de obiecte de acest tip. Crearea obiectelor se realizeaza prin instantierea unei clase si presupune doua etape: declarare si instantiere.
Prima etapa presupune declararea tipului de data pentru obiectul nou creat.
nume_clasa nume_obiect;
Cea de-a doua etapa este realizata prin intermediul operatorului de instantiere new. Operatorul new aloca dinamic memorie pentru obiectul creat si returneaza o referinta catre acesta. Tot in aceasta etapa este apelat unul din constructorii clasei, care initializeaza starea unui obiect imediat dupa crearea sa.
nume_obiect = new constructor();
Crearea unui obiect poate fi realizata si intr-o singura linie de cod, de genul:
nume_clasa nume_obiect = new constructor();
Constructorul este un tip special de metoda, care are acelasi nume ca si clasa in care este definit si care nu are tip returnat. Metodele constructor sunt apelate in momentul in care sunt create instante ale clasei. Daca nu este definita o metoda constructor pentru o clasa, compilatorul va crea o astfel de metoda. Constructorul implicit nu are lista de parametri, iar corpul metodei este vid. Rolul principal al constructorului este acela de a realiza initializarea variabilelor instanta ale unui obiect, cand acesta este creat.
class Cerc { | |
static final double PI = 3.14; | |
static int count = 0; | |
int x; | |
int y; | |
int raza; | |
// metoda constructor 1 | |
Cerc() { | |
x = 0; | |
y = 0; | |
raza = 0; | |
} | |
// metoda constructor 2 | |
Cerc(int x0, int y0, int raza0) { | |
x = x0; | |
y = y0; | |
raza = raza0; | |
} | |
// metoda non-statica | |
public double aria() { | |
return PI * raza * raza; | |
} | |
// metoda statica | |
static int nrObiecte() { | |
return count; | |
} | |
public static void main(String[] args) { | |
Cerc c = new Cerc(2, 5, 4); | |
System.out.println(c.raza); | |
} | |
} |
Referirea atributelor si metodelor de instanta pentru un obiect se face astfel:
nume_obiect.atribut; nume_obiect.nume_metoda();
Limbajul Java permite definirea de constructori multipli intr-o clasa, prin intermediul polimorfismului. De exemplu, intr-o clasa care defineste numere complexe putem utiliza un constructor pentru a initializa partea reala si partea imaginara cu valoarea 0.0, si un alt constructor care permite utilizatorului sa specifice valorile initiale pentru partea reala, respectiv imaginara.
class Complex { | |
Complex() { | |
parteaReala = 0.0; | |
parteaImaginara = 0.0; | |
} | |
Complex(double real, double imag) { | |
parteaReala = real; | |
parteaImaginara = imag; | |
} | |
private double parteaReala; | |
private double parteaImaginara; | |
} |