1. Właściwości: getter i setter

Kiedy duży projekt jest rozwijany przez kilkudziesięciu programistów jednocześnie, często pojawia się problem z tym, że mają oni różne podejście do danych, które są przechowywane w polach klasy.

Nikt szczegółowo nie studiuje dokumentacji klasy lub może ona nie opisywać wszystkich przypadków, dlatego często mogą wystąpić sytuacje, gdy dane wewnątrz obiektu zostaną „uszkodzone” i obiekt stanie się nieważny.

Aby uniknąć takich sytuacji, w Javie zwyczajowo ustawia się wszystkie pola klasy jako prywatne . Tylko metody klasowe mogą zmieniać zmienne klasowe i żadne metody z innych klas nie mają bezpośredniego dostępu do zmiennych klasowych. Lubię to.

Jeśli chcesz, aby inne klasy mogły pobierać lub zmieniać dane wewnątrz obiektów Twojej klasy, musisz dodać dwie metody do kodu swojej klasy — metodę get i metodę set. Przykład:

Kod Notatka
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;
   }
}


private-nazwa pola



Inicjalizacja pola poprzez konstruktor


getName()- metoda zwraca wartość nazwy pola




setName()- metoda zmienia wartość nazwy pola

Żadna inna klasa nie może bezpośrednio zmienić wartości pola nazwy. Jeśli ktoś chce uzyskać wartość pola name, będzie musiał wywołać metodę getName() na obiekcie typu Person. Jeśli jakiś kod chce zmienić wartość pola name, będzie musiał wywołać metodę setName() na obiekcie typu Person.

Metoda getName()jest również nazywana „ pobieraczem pola nazwy ”, a metoda setName()nazywana jest „ ustawiaczem pola nazwy ”.

To bardzo powszechne podejście. W 80-90% całego kodu Java nigdy nie zobaczysz zmiennych klasy publicznej. Zamiast tego zostaną zadeklarowane private(well lub protected), a każda zmienna będzie miała publiczne gettery i settery.

Takie podejście sprawia, że ​​kod jest dłuższy, ale bardziej niezawodny.

Bezpośredni dostęp do zmiennej klasowej jest jak przechodzenie przez podwójną bryłę : jest prostszy i szybszy, ale jeśli wszyscy to zrobią, wszyscy będą na tym gorsi.

Powiedzmy, że chcesz utworzyć klasę opisującą punkt na płaszczyźnie xi y. Oto jak zrobiłby to początkujący programista:

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

A oto jak zrobiłby to doświadczony programista Java:

Kod
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;
   }
}

Czy kod stał się dłuższy? Niewątpliwie.

Ale możesz dodać walidację parametrów do seterów i getterów. Na przykład możesz zapewnić, że xi ysą zawsze większe od zera (lub nie mniejsze od zera). Przykład:

Kod Notatka
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. Czas życia obiektu

Wiesz już, że obiekty są tworzone za pomocą operatora new, ale w jaki sposób obiekty są usuwane? Nie istnieją wiecznie – nie wystarczy na to żadna pamięć.

Wiele języków programowania, takich jak C++, ma specjalny operator do usuwania obiektu delete. A jak wygląda sytuacja z tym w Javie?

W Javie wszystko jest zorganizowane trochę inaczej i nie ma w Javie operatora usuwania. Czy to oznacza, że ​​obiekty w Javie nie są usuwane? Nie, oczywiście są usuwane. W przeciwnym razie aplikacjom Java szybko zabrakłoby pamięci i nie byłoby mowy o miesiącach nieprzerwanej pracy.

W Javie proces usuwania obiektów jest całkowicie zautomatyzowany – usuwaniem obiektów zajmuje się sama maszyna Java . Taki proces nazywa się Garbage Collection (garbage collection), a mechanizm zbierający śmieci nazywa się Garbage Collector - Garbage Collector lub w skrócie GC .

Skąd więc maszyna Java wie, że jakiś obiekt musi zostać usunięty i kiedy?

Garbage collector dzieli wszystkie obiekty na osiągalne i nieosiągalne. Jeśli obiekt ma co najmniej jedno odniesienie, jest uważany za osiągalny. Jeśli nie ma ani jednej zmiennej, która odnosiłaby się do obiektu, taki obiekt jest uważany za nieosiągalny i jest uznawany za śmieci: oznacza to, że można go usunąć.

W Javie nie można wziąć i utworzyć odniesienia do istniejącego obiektu: można go tylko przypisać. Jeśli usunęliśmy wszystkie odniesienia do obiektu, zostaje on utracony na zawsze.

Referencje cykliczne

Poprzednia logika brzmi świetnie, dopóki nie znajdziemy prostego kontrprzykładu: mamy dwa obiekty, które odwołują się do siebie (przechowują odniesienia do siebie). Nikt inny nie przechowuje żadnych odniesień do tych obiektów.

Nie można uzyskać dostępu do tych obiektów z pozostałej części kodu, ale nadal istnieją odwołania.

Dlatego Garbage Collector dzieli obiekty nie na „obiekty z referencjami” i „obiekty bez referencji”, ale na osiągalne i nieosiągalne.

Osiągalne obiekty

Najpierw te obiekty, które są w 100% żywe, są dodawane do listy osiągalnych. Na przykład bieżący wątek ( Thread.current()) lub Konsola ( System.in).

Lista osiągalnych obiektów jest następnie dodawana do tych, do których odwołują się pierwsze osiągalne obiekty. Następnie te, o których mowa w drugim, i tak dalej.

Zatem jeśli istnieje pewna grupa obiektów, które tylko się do siebie odnoszą, ale nie ma możliwości dostania się do nich z obiektów osiągalnych, takie obiekty zostaną uznane za śmieci i zostaną usunięte.


3. Wywóz śmieci

Fragmentacja pamięci

Kolejnym ważnym punktem związanym z usuwaniem obiektów jest fragmentacja pamięci. Jeśli ciągle tworzysz i usuwasz obiekty, wkrótce cała pamięć zostanie pomieszana: obszary zajętej pamięci będą stale przeplatane pustymi obszarami.

A łatwo może się zdarzyć, że nie uda nam się stworzyć dużego obiektu (na przykład tablicy zawierającej milion elementów), bo nie ma dużego kawałka wolnej pamięci. Te. wydaje się, że jest wolna pamięć i to dużo, ale może nie być całego dużego fragmentu wolnej pamięci

Optymalizacja pamięci (defragmentacja)

Maszyna Java rozwiązuje ten problem w określony sposób. Wygląda to mniej więcej tak:

Pamięć jest podzielona na dwie części. Wszystkie obiekty są tworzone (i usuwane) tylko w jednej połowie. Kiedy przychodzi czas na oczyszczenie dziur w pamięci, wszystkie obiekty z pierwszej połowy są kopiowane do drugiej połowy. Ale są już skopiowane blisko siebie, więc nie ma dziur.

Proces ten wygląda następująco:

Etap 1: Po utworzeniu obiektów

Zbieranie śmieci w Javie

Etap 2: Pojawienie się „dziur”

Zbieranie śmieci w Javie

Etap 3: Likwidacja „dziur”

Zbieranie śmieci w Javie

W ten sposób nie trzeba nawet usuwać obiektów. Maszyna Java po prostu kopiuje wszystkie osiągalne obiekty do nowej lokalizacji i deklaruje, że cały obszar pamięci ze starymi obiektami jest wolny.