1. Proprietăți: getters și setters

Atunci când un proiect mare este dezvoltat de zeci de programatori în același timp, adesea apar probleme dacă aceștia gestionează diferit datele stocate în câmpurile de clasă.

Poate că oamenii nu reușesc să studieze documentația de clasă în detaliu, sau poate că nu descrie fiecare caz. Ca urmare, există situații frecvente în care datele interne ale unui obiect pot deveni „corupte”, făcând obiectul invalid.

Pentru a evita aceste situații, se obișnuiește ca toate câmpurile de clasă să fie private în Java . Numai metodele clasei pot modifica variabilele clasei. Nicio metodă din alte clase nu poate accesa direct variabilele.

Dacă doriți ca alte clase să poată obține sau modifica datele din interiorul obiectelor clasei dvs., trebuie să adăugați două metode la clasa dvs. - o metodă get și o metodă set. Exemplu:

Cod Notă
class Person
{
   private String name;

   public Person(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return name;
   }

   public void setName(String name)
   {
      this.name = name;
   }
}


privatecâmp de nume



Inițializarea câmpului prin constructor


getName()— Această metodă returnează valoarea câmpului de nume




setName()— Această metodă modifică valoarea câmpului de nume

Nicio altă clasă nu poate schimba direct valoarea câmpului de nume. Dacă cineva trebuie să obțină valoarea câmpului de nume, va trebui să apeleze metoda getName() pe un Personobiect. Dacă un cod dorește să schimbe valoarea câmpului de nume, va trebui să apeleze setName() metoda pe un Personobiect.

Metoda getName()este numită și „ setter pentru câmpul de nume”, iar metoda setName()este numită „ setter pentru câmpul de nume”.

Aceasta este o abordare foarte comună. În 80-90% din tot codul Java, nu veți vedea niciodată variabile publice într-o clasă. În schimb, acestea vor fi declarate private(sau protected), iar fiecare variabilă va avea getters și setters publici.

Această abordare face codul mai lung, dar mai fiabil.

Accesarea directă a unei variabile de clasă este ca și cum ai întoarce mașina prin linii galbene duble : este mai ușor și mai rapid, dar dacă toată lumea o face, atunci lucrurile se înrăutățesc pentru toată lumea.

Să presupunem că doriți să creați o clasă care descrie un punct ( x, y). Iată cum ar face un programator începător:

class Point
{
   public int x;
   public int y;
}

Iată cum ar face acest lucru un programator Java experimentat:

Cod
class Point {
   private int x;
   private int y;

   public Point(int x, int y) {
      this.x = x;
      this.y = y;
   }

   public int getX() {
      return x;
   }

   public void setX(int x) {
      this.x = x;
   }

   public int getY() {
      return y;
   }

   public void setY(int y) {
      this.y = y;
   }
}

Codul este mai lung? Fara indoiala.

Dar puteți adăuga validarea parametrilor la getters și setters. De exemplu, vă puteți asigura că xși ysunt întotdeauna mai mari decât zero (sau nu mai mici decât zero). Exemplu:

Cod Notă
class Point {
   private int x;
   private int y;

   public Point(int x, int y) {
      this.x = x < 0 ? 0 : x;
      this.y = y < 0 ? 0 : y;
   }

   public int getX() {
      return x;
   }

   public void setX(int x) {
      this.x = x < 0 ?  0 : x;
   }

   public int getY() {
      return y;
   }

   public void setY(int y) {
      this.y = y < 0 ? 0 : y;
   }
}


2. Durata de viață a obiectului

Știți deja că obiectele sunt create folosind newoperatorul, dar cum sunt șterse obiectele? Ele nu există pentru totdeauna. Nu există suficientă memorie pentru asta.

În multe limbaje de programare, cum ar fi C++, există un deleteoperator special pentru ștergerea obiectelor. Dar cum funcționează asta în Java?

În Java, totul este aranjat puțin diferit. Java nu are operator de ștergere. Înseamnă asta că obiectele nu sunt șterse în Java? Nu, sunt șterse, desigur. În caz contrar, aplicațiile Java ar rămâne rapid fără memorie și nu s-ar vorbi despre programe care rulează fără întrerupere timp de luni de zile.

În Java, ștergerea obiectelor este complet automatizată. Mașina Java însăși se ocupă de ștergerea obiectelor. Acest proces se numește colectare de gunoi, iar mecanismul care colectează gunoiul se numește colector de gunoi ( GC ).

Deci, cum știe mașina Java când să șterge un obiect?

Colectorul de gunoi împarte toate obiectele în „accesibil” și „inaccesibil”. Dacă există cel puțin o referință la un obiect, acesta este considerat accesibil. Dacă nu există o variabilă care să se refere la un obiect, obiectul este considerat inaccesibil și este declarat gunoi, ceea ce înseamnă că poate fi șters.

În Java, nu puteți crea o referință la un obiect existent - puteți aloca doar referințe pe care le aveți deja. Dacă ștergem toate referințele la un obiect, atunci acesta se pierde pentru totdeauna.

Referințe circulare

Această logică sună grozav până când găsim un contraexemplu simplu: să presupunem că avem două obiecte care se referă unul la celălalt (stochează referințe unul la celălalt). Niciun alt obiect nu stochează referințe la aceste obiecte.

Aceste obiecte nu pot fi accesate din cod, dar sunt încă referite.

Acesta este motivul pentru care colectorul de gunoi împarte obiectele în accesibile și inaccesibile, mai degrabă decât „referențiate” și „nereferențiate”.

Obiecte accesibile

În primul rând, obiectele care sunt 100% vii sunt adăugate la lista accesibilă. De exemplu, firul curent ( Thread.current()) sau InputStream de consolă ( System.in).

Apoi lista de obiecte accesibile se extinde pentru a include obiecte la care se referă setul inițial de obiecte accesibile. Apoi este extins din nou pentru a include obiecte la care se referă acest set mărit și așa mai departe.

Asta înseamnă că, dacă există unele obiecte care se referă doar unele la altele, dar nu există nicio modalitate de a ajunge la ele de la obiecte accesibile, atunci acele obiecte vor fi considerate gunoi și vor fi șterse.


3. Colectarea gunoiului

Fragmentarea memoriei

Un alt punct important legat de ștergerea obiectelor este fragmentarea memoriei. Dacă creați și ștergeți în mod constant obiecte, în curând memoria va fi puternic fragmentată: zonele de memorie ocupată vor fi intercalate cu zone de memorie neocupată.

Ca rezultat, putem ajunge cu ușurință într-o situație în care nu putem crea un obiect mare (de exemplu, o matrice cu un milion de elemente), deoarece nu există o bucată mare de memorie liberă. Cu alte cuvinte, poate exista memorie liberă, chiar și multă, dar poate să nu existe un bloc mare de memorie liberă învecinată

Optimizarea memoriei (defragmentare)

Mașina Java rezolvă această problemă într-un mod specific. Arata cam asa:

Memoria este împărțită în două părți. Toate obiectele sunt create (și șterse) în doar jumătate din memorie. Când vine timpul să curățați găurile din memorie, toate obiectele din prima jumătate sunt copiate în a doua jumătate. Dar sunt copiate unul lângă altul, astfel încât să nu existe găuri.

Procesul arată aproximativ astfel:

Pasul 1: După crearea obiectelor

Colectarea gunoiului în Java

Pasul 2: Apariția „găurilor”

Colectarea gunoiului în Java 2

Pasul 3: Eliminarea „găurilor”

Colectarea gunoiului în Java 3

Și de aceea nu trebuie să ștergeți obiecte. Mașina Java pur și simplu copiază toate obiectele accesibile într-o nouă locație și eliberează întreaga zonă de memorie în care obiectele erau stocate.