Clase și obiecte în Java
Java este un limbaj orientat pe obiecte, ceea ce înseamnă că noțiunile de „clasă” și „obiect” joacă un rol central. Orice program Java poate fi privit ca un ansamblu de obiecte care interacționează între ele.
Un șablon sau descriere a unui obiect este clasa, iar un obiect este o instanță a acestei clase. Putem face o analogie cu ideea de om: avem o noțiune generală despre om – două mâini, două picioare, cap, trunchi etc. Acest șablon reprezintă clasa. Un om real (o instanță a acestui șablon) este un obiect al clasei.
O clasă este definită cu ajutorul cuvântului cheie class:
class Person{
}
În acest caz, clasa se numește Person. După numele clasei urmează acoladele care conțin corpul clasei – adică câmpurile și metodele sale.
Orice obiect poate avea două caracteristici principale: stare – datele stocate de obiect și comportament – acțiunile pe care le poate face obiectul.
Pentru a stoca starea obiectului, în clasa se folosesc câmpuri sau variabile de clasă. Pentru a defini comportamentul obiectului, se utilizează metode. De exemplu, o clasă Person, care reprezintă o persoană, ar putea avea următoarea definiție:
class Person{
String name; // nume
int age; // vârstă
void displayInfo(){
System.out.printf("Name: %s \tAge: %d\n", name, age);
}
}
În clasa Person sunt definite două câmpuri: name (care reprezintă numele persoanei) și age (vârsta). De asemenea, este definită o metodă displayInfo care afișează aceste informații în consolă.
Acum să folosim această clasă într-un program:
public class Program{
public static void main(String[] args) {
Person tom;
}
}
class Person{
String name; // nume
int age; // vârstă
void displayInfo(){
System.out.printf("Name: %s \tAge: %d\n", name, age);
}
}
De obicei, clasele sunt definite în fișiere separate. În acest caz, pentru simplitate, am definit două clase în același fișier. Observați că doar una dintre clase poate avea modificatorul public (în acest caz, clasa Program), iar fișierul de cod trebuie să poarte numele acestei clase, adică Program.java.
Clasa reprezintă un nou tip, astfel încât putem defini variabile care reprezintă acest tip. De exemplu, în metoda main este definită variabila tom, care reprezintă clasa Person. Dar momentan această variabilă nu indică niciun obiect și, implicit, are valoarea null. Înainte de a o putea utiliza, trebuie să creăm un obiect al clasei Person.
Constructori
Pe lângă metodele obișnuite, clasele pot defini metode speciale numite constructori. Constructorii sunt apelați atunci când se creează un nou obiect al clasei respective și inițializează obiectul.
Dacă într-o clasă nu este definit niciun constructor, atunci pentru acea clasă este generat automat un constructor fără parametri.
Clasa Person definită mai sus nu are constructori, astfel că se generează automat un constructor implicit. Putem folosi acest constructor pentru a crea un obiect Person. De exemplu:
public class Program{
public static void main(String[] args) {
Person tom = new Person(); // crearea obiectului
tom.displayInfo();
// modificăm numele și vârsta
tom.name = "Tom";
tom.age = 34;
tom.displayInfo();
}
}
class Person{
String name; // nume
int age; // vârstă
void displayInfo(){
System.out.printf("Name: %s \tAge: %d\n", name, age);
}
}
Pentru a crea un obiect Person, folosim expresia new Person(). Operatorul new alocă memorie pentru obiectul Person. Apoi este apelat constructorul implicit, care nu primește parametri. După executarea acestei expresii, este alocat un spațiu în memorie pentru stocarea datelor obiectului, iar variabila tom primește o referință la obiectul creat.
Dacă constructorul nu inițializează valorile variabilelor, acestea primesc valori implicite: 0 pentru tipurile numerice și null pentru șiruri și alte clase.
În final, în consolă vom vedea:
Name: null Age: 0
Name: Tom Age: 34
Dacă este necesar ca la crearea unui obiect să fie executată o anumită logică, de exemplu, pentru ca anumite câmpuri ale clasei să primească anumite valori, putem defini propriii constructori în clasă. De exemplu:
public class Program{
public static void main(String[] args) {
Person bob = new Person(); // apelul primului constructor fără parametri
bob.displayInfo();
Person tom = new Person("Tom"); // apelul celui de-al doilea constructor cu un parametru
tom.displayInfo();
Person sam = new Person("Sam", 25); // apelul celui de-al treilea constructor cu doi parametri
sam.displayInfo();
}
}
class Person{
String name; // nume
int age; // vârstă
Person() {
name = "Undefined";
age = 18;
}
Person(String n) {
name = n;
age = 18;
}
Person(String n, int a) {
name = n;
age = a;
}
void displayInfo() {
System.out.printf("Name: %s \tAge: %d\n", name, age);
}
}
Acum, în clasa Person, sunt definiți trei constructori, fiecare dintre aceștia acceptând un număr diferit de parametri și setând valorile câmpurilor clasei.
Rezultatul în consola programului:
Name: Undefined Age: 18
Name: Tom Age: 18
Name: Sam Age: 25
Acest exemplu arată cum diferitele versiuni ale constructorului permit inițializarea obiectelor cu valori implicite sau personalizate, în funcție de numărul și tipul parametrilor transmiși.
Cuvântul cheie this
Cuvântul cheie this reprezintă o referință la instanța curentă a clasei. Prin acest cuvânt, putem accesa variabilele, metodele obiectului și chiar apelăm constructorii săi.
public class Program{
public static void main(String[] args) {
Person undef = new Person();
undef.displayInfo();
Person tom = new Person("Tom");
tom.displayInfo();
Person sam = new Person("Sam", 25);
sam.displayInfo();
}
}
class Person{
String name; // имя
int age; // возраст
Person()
{
this("Undefined", 18);
}
Person(String name)
{
this(name, 18);
}
Person(String name, int age)
{
this.name = name;
this.age = age;
}
void displayInfo(){
System.out.printf("Name: %s \tAge: %d\n", name, age);
}
}
În al treilea constructor, parametrii se numesc la fel ca și câmpurile clasei. Pentru a distinge între câmpurile clasei și parametrii, se folosește cuvântul cheie this:
this.name = name;
În acest caz, indicăm că valoarea parametrului name este atribuită câmpului name al obiectului.
De asemenea, avem trei constructori care fac același lucru: setează câmpurile name și age. Pentru a evita repetarea codului, putem folosi this pentru a apela unul dintre constructorii clasei și a transmite valorile necesare pentru parametrii săi:
Person(String name) {
this(name, 18);
}
Rezultatul programului va fi același ca în exemplul anterior.
Inițializatori
Pe lângă constructor, inițializarea obiectului poate fi realizată și cu ajutorul unui inițializator. Inițializatorul este executat înainte de orice constructor și conține cod comun pentru toți constructorii:
public class Program{
public static void main(String[] args) {
Person undef = new Person();
undef.displayInfo();
Person tom = new Person("Tom");
tom.displayInfo();
}
}
class Person{
String name; // nume
int age; // vârstă
/* începutul blocului de inițializator */
{
name = "Undefined";
age = 18;
}
/* sfârșitul blocului de inițializator */
Person() {
}
Person(String name) {
this.name = name;
}
Person(String name, int age) {
this.name = name;
this.age = age;
}
void displayInfo() {
System.out.printf("Name: %s \tAge: %d\n", name, age);
}
}
Rezultatul afișat în consolă:
Name: Undefined Age: 18
Name: Tom Age: 18
Inițializatorul permite rularea unui cod comun pentru toți constructorii, astfel încât toate obiectele primesc valori inițiale fără a repeta codul în fiecare constructor.