This is an old revision of the document!
Presupunem că dorim să descriem, uzitând un limbaj de programare, un obiect carte. În general, o carte poate fi caracterizată prin titlu, autor și editură. Cum am putea realiza această descriere formală?
Dacă descriem acest obiect, tip abstract de date, într-un limbaj de programare structural, spre exemplu limbajul C, atunci vom crea, ca mai jos, o structură Carte
împreună cu o serie de funcții cuplate de această structură. Cuplajul este realizat prin faptul că orice funcție care operează asupra unei cărți conține în lista sa de argumente o variabilă de tip Carte
.
typedef struct carte { char *titlu, *autor; int nr_pagini; }*Carte; void initializare(Carte this, char* titlu, char* autor, int nr_pagini) { this->titlu = strdup(titlu); this->autor = strdup(autor); this->nr_pagini = nr_pagini; } void afisare(Carte this) { printf("%s, %s - %d\n", this->autor, this->titlu, this->nr_pagini); }
Dacă modelăm acest obiect într-un limbaj orientat pe obiecte (în acest caz, Java), atunci vom crea o clasă Carte
ca mai jos.
class Carte { String nume, autor; int nr_pagini; public Carte(String nume, String autor, int nr_pagini) { this.nume = nume; this.autor = autor; this.nr_pagini = nr_pagini; } public Carte() { this("Enigma Otiliei", "George Calinescu", 423); } public String toString() { return this.autor + ", " + this.nume + " - " + this.nr_pagini; } public static void main(String args[]) { Carte carte; carte = new Carte("Poezii", "Mihai Eminescu", 256); System.out.println(carte); } }
class
urmat de numele clasei.class <class_name> { field; method; }
Datele nume
, autor
, nr_pagini
definite în clasa Carte
se numesc atribute, date-membru, variabile-membru sau câmpuri, iar operațiile toString
și main
se numesc metode.
Fiecare clasă are un set de constructori care se ocupă cu instanțierea (inițializarea) obiectelor nou create. De exemplu, clasa Carte
are doi constructori: unul cu trei parametri și unul fără parametri care îl apelează pe cel cu trei parametri.
new
și are ca efect crearea efectivă a obiectului cu alocarea spațiului de memorie corespunzător.Carte
are propriile sale atribute.new
este apelat constructorul specificat. Parantezele rotunde după numele clasei indică faptul că acolo este, de fapt, un apel la unul din constructorii clasei și nu simpla specificare a numelui clasei.
new
.
class Point { int x, y; public Point(int x, int y) { this.x = x; this.y = y; } } class Dimension { int width, height; public Dimension(int width, int height) { this.width = width; this.height = height; } } class Rectangle { Point p; Dimension d; public Rectangle(Point p, Dimension d) { this.p = p; this.d = d; } public static void main(String args[]) { Rectangle patrat = new Rectangle(new Point(0, 0), new Dimension(10, 10)); } }
carte
spre un obiect de tip Carte
se face în felul următor: Carte carte;
null
, ce înseamnă niciun obiect referit, nu este atribuită automat tuturor variabilelor referința la declararea lor. Regula este următoarea: dacă referința este un membru al unei clase și ea nu este inițializată în niciun fel, la instanțierea unui obiect al clasei respective, referința va primi implicit valoarea null
. Dacă însă referința este o variabilă locală ce aparține unei metode, inițializarea implicită nu mai funcționeaza. De aceea, se recomandă ca programatorul să realizeze intotdeauna o inițializare explicită a obiectelor.
toString
nu este toString(carte)
, ci carte.toString()
întrucât metoda toString
aparține obiectului referit de carte
- se apelează metoda toString
pentru obiectul referit de variabila carte
.Carte
precum și trei referințe spre acest tip de obiecte. Carte
are alocată o zonă proprie de memorie, în care sunt stocate valorile câmpurilor nume
, autor
, nr_pagini
. Ultima referință definită în exemplul de mai jos, c3
, va referi și ea exact același obiect ca c2
, adică al doilea obiect creat.
class Test { public static void main(String args[]) { Carte c1 = new Carte("Poezii", "Mihai Eminescu", 326); Carte c2 = new Carte("Camil Petrescu", "George Calinescu", 426); Carte c3 = c2; c3.autor = "George Calinescu"; System.out.println(c1); System.out.println(c2); System.out.println(c3); } }
c3 = c2
nu a făcut altceva decât să atașeze referinței c3
obiectul având aceeași identitate precum cel referit de c2
, adică obiectul secund creat.
Clasele, așa cum am văzut deja, sunt definite folosind cuvântul cheie class
. În următoarele secțiuni, vom vorbi despre diferite categorii de membri care pot apărea în interiorul unei clase.
class Carte { private String autor, nume; public Carte(String autor, String nume) { this.autor = autor; this.nume = nume; } public String toString() { return "Autor: " + autor + "\n" + "Titlul: " + nume; } } class Creion { private String culoare; public String getCuloare() { return culoare; } } class Test { public static void main(String args[]) { Carte c1, c2; c1 = new Carte(); //EROARE, deoarece nu avem constructor de aritate 0 c2 = new Carte("George Calinescu", "Enigma Otiliei"); //CORECT Creion c3; c3 = new Creion(); //CORECT, deoarece nu am definit niciun constructor => exista cel predefinit } }
Atunci când definim o clasă, specificăm felul în care obiectele de tipul acelei clase arată și se comportă. Dar până la crearea efectivă a unui obiect, folosind new
, nu se alocă nicio zonă de memorie pentru atributele definite în cadrul clasei, iar la crearea unui obiect se alocă acestuia memoria necesară pentru fiecare atribut existent în clasa instanțiată. Tot până la crearea efectivă a unui obiect nu putem beneficia de serviciile definite în cadrul unei clase. Ei bine, există și o excepție de la regula prezentată anterior - membrii statici (atribute și metode) ai unei clase. Acești membri ai unei clase pot fi folosiți direct prin intermediul numelui clasei, fără a deține instanțe pentru respectiva clasă.
Un membru al unei clase (atribut sau metodă) este static dacă el este precedat de cuvântul cheie static
.
Din interiorul unei metode statice pot fi accesați doar alți membri statici ai clasei în care este definită metoda, accesarea membrilor nestatici ai clasei producând o eroare de compilare.
Trebuie avut în vedere contextul static al metodei main. Dintr-un context static nu se pot apela funcții nestatice, în schimb, se pot crea obiecte ale oricărei clase.
În Java, se pot găsi două sau mai multe metode, în cadrul aceleiași clase, care să aibă același nume, atâta timp cât argumentele lor sunt diferite. În acest caz, se spune că metoda este supraîncărcată, iar procedeul se numește supraîncarcarea metodelor. Pentru o mai bună înțelegere a acestui principiu POO, se va oferi, în continuare, un exemplu pentru o metodă care determină maximul.
class Test { public int maxim(int a, int b) { if(a > b) return a; else return b; } public int maxim(String s1, String s2) { if(s1.compareTo(s2) < 0) return 2; else return 1; } public int maxim(int a, int b, int c) { if(maxim(a, b) < c) return c; else return maxim(a, b); } }
Un alt exemplu elocvent, pentru acest prinicpiu POO, este operatorul +
care execută operații diferite în cotexte diferite.